【问题标题】:Bash- parse file into arraysBash-将文件解析为数组
【发布时间】:2012-12-01 10:31:18
【问题描述】:

我有这个文件

Seq1
10 1 5
10 2 6
10 3 9
Seq2
15 2 7
15 4 9
15 8 12

我想为每个 Seq (Seq1, Seq2) 设置这样的数组:

2ndColumn=(1,2,3) 
3rdColumn=(5,6,9)

我写了这个,但它不会破坏 while 循环..

#!/bin/bash
2ndColumn=()
3rdColumn=()
while read line 
do
if [[ $line == S* ]] 
 echo "$line"
else
 i=0
 while [[ $line != S* ]]
 do
  2ndColumn[i]="$(echo $line | cut -d\  -f2)"
  3rdColumn[i]="$(echo $line | cut -d\  -f3)"
  i=$((i+1))
  read line
 done
 echo "${2ndColumn[@]} and ${3rdColumn[@]}"
fi
done < file
exit 0

此脚本将永远迭代,它不会退出 while 循环。请帮帮这个愚蠢的人:(

【问题讨论】:

  • 你永远循环的原因是你的内部循环从不检查read是成功还是失败。
  • @Barmar 为什么 while 还不够?
  • 读取失败时,line设置为空字符串,[[ $line != S* ]]为真,所以while循环一直循环。外循环使用read 的成功作为其while 条件。

标签: linux arrays bash fileparsing


【解决方案1】:

我会重组它以使用单个循环,而不是在标准输入上使用嵌套读取调用的嵌套循环:

2ndColumn=()
3rdColumn=()
i=0
while read line 
do
    if [[ $line == S* ]] 
        echo "$line ==> ${2ndColumn[@]} and ${3rdColumn[@]}"
        # reset the lists...
        2ndColumn=()
        3rdColumn=()
        i=0
    else
        2ndColumn[i]="$(echo $line | cut -d\  -f2)"
        3rdColumn[i]="$(echo $line | cut -d\  -f3)"
        i=$((i+1))
    fi
done

这将避免内部读取调用的问题,该调用可能在输入标准输入文件句柄时被阻塞。

【讨论】:

    【解决方案2】:
    • 您不能更改while read光标

    我为你写了这篇文章,用了一点 来为数组名称加上 seq N+1 前缀:

    #!/bin/bash
    
    file=file.txt
    
    while read line; do
        if [[ $line == S* ]]; then
            echo "$line"
            i=0
            ((Seq++))
        else
            declare seq${Seq}_2ndColumn[i]="$(echo $line | cut -d\  -f2)"
            declare seq${Seq}_3rdColumn[i]="$(echo $line | cut -d\  -f3)"
            ((i++))
        fi
    done < "$file"
    
    echo "${!seq*} arrays are declared"
    

    输出

    seq1_2ndColumn seq1_3rdColumn seq2_2ndColumn seq2_3rdColumn arrays are declared
    

    解释

    • ${!pattern*} 是 bash 的一个很好的功能,可以显示以 pattern 开头的变量
    • (( )) 是一个算术命令,如果表达式非零,则返回退出状态 0,如果表达式为零,则返回 1。如果需要副作用(分配),也用作“让”的同义词。见http://mywiki.wooledge.org/ArithmeticExpression

    奖金

    如果您可以控制数组中的内容,请尝试在最后执行此操作::

    for s in ${!seq*}; do
        printf '\t%s\n' $(eval echo \${$s[@]})
    done
    

    见见http://mywiki.wooledge.org/BashFAQ/048

    新的输出

    seq1_2ndColumn
            1
            2
            3
    seq1_3rdColumn
            5
            6
            9
    seq2_2ndColumn
            2
            4
            8
    seq2_3rdColumn
            7
            9
            12
    

    【讨论】:

      【解决方案3】:
      file=/PATH/TO/file.txt
      
      arr1=( $(awk '/^Seq/{l++} l==1{print $2}' "$file") )
      arr2=( $(awk '/^Seq/{l++} l==1{print $3}' "$file") )
      
      echo "arr1:"
      printf '\t%s\n' ${arr1[@]}
      
      echo "arr2:"
      printf '\t%s\n' ${arr2[@]}
      

      【讨论】:

      • 嘿,斯普特尼克。据我了解,您的解决方案将一次将所有值放入数组中,但我必须获取与标题相关的两个数组(Seq1,Seq2 ..),以便我将引入另一个计算..
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-03
      • 1970-01-01
      • 1970-01-01
      • 2014-10-19
      • 2014-06-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多