【问题标题】:Bash, wihle read line by line, split strings on line divided by ",", store to arrayBash,在逐行读取的同时,将字符串分割为“,”,存储到数组
【发布时间】:2019-10-25 15:04:18
【问题描述】:

我需要逐行读取文件,每行用“,”分隔,并存储到数组中。

文件源文件。

usl-coop,/root
usl-dev,/bin

脚本。

i=1
while read -r line; do
IFS="," read -ra para_$i <<< $line
echo ${para_$i[@]}
((i++))
done < source_file

预期输出。

para_1[0]=usl-coop
para_1[1]=/root
para_2[0]=usl-dev
para_2[1]=/bin

脚本会输出关于 echo 的错误。

./sofimon.sh: line 21: ${para_$i[@]}: bad substitution

当我一个一个地回显数组时,例如

echo para_1[0]

它表明,变量被存储了。

但我需要将它与内部变量一起使用,就像这样。

${para_$i[1]}

可以这样做吗?

谢谢。

S.

【问题讨论】:

    标签: arrays bash variables while-loop


    【解决方案1】:

    这是一个简短的 awk 脚本,用于执行该任务。

    awk 'BEGIN{FS=",";of="para_%d[%d]=%s\n"}{printf(of, NR, 0, $1);printf(of, NR, 1, $2)}' input.txt
    

    提供所需的输出。

    解释:

    BEGIN{
      FS=",";                # set field seperator to `,`
      of="para_%d[%d]=%s\n"  # define common printf output format
    }
    {                         # for each input line
      printf(of, NR, 0, $1);  # output for current line, [0], left field
      printf(of, NR, 1, $2)   # output for current line, [1], right field
    } 
    

    【讨论】:

      【解决方案2】:

      使用associative arrays 模拟二维数组有一个技巧。它工作得很好,我认为是最灵活和可扩展的:

      declare -A para
      i=1
      while IFS=, read -r -a line; do
          for j in ${!line[@]}; do
             para[$i,$j]="${line[$j]}"
          done
         ((i++)) ||:
      done < source_file
      declare -p para
      

      将输出:

      declare -A para=([1,0]="usl-coop" [1,1]="/root" [2,1]="/bin" [2,0]="usl-dev" )
      

      无需大量修改脚本,您就可以使用indirect variable expansion。它有时用于更简单的脚本中:

      i=1
      while IFS="," read -r -a para_$i; do
              n="para_$i[@]"
              echo "${!n}"
              ((i++)) ||:
      done < source_file
      declare -p ${!para_*}
      

      或与 nameref a named reference to another variable 基本相同(旁注:请参阅[@] 在间接扩展中如何成为变量的一部分,但在命名引用中却不是):

      i=1
      while IFS="," read -r -a para_$i; do
              declare -n n
              n="para_$i"
              echo "${n[@]}"
              ((i++)) ||:
      done < source_file
      declare -p ${!para_*}
      

      上面的两个脚本都会输出相同的:

      usl-coop /root
      usl-dev /bin
      declare -a para_1=([0]="usl-coop" [1]="/root")
      declare -a para_2=([0]="usl-dev" [1]="/bin")
      

      也就是说,我认为您根本不应该将文件读入内存。这只是一个糟糕的设计。 Shell 和 bash 是围绕通过管道、流、fifos、重定向、进程替换等传递文件而构建的,而无需保存/复制/存储文件。如果您有要解析的文件,则应将其流式传输到另一个进程,解析并保存结果,而无需将整个输入存储在内存中。如果您想在文件中找到一些数据,请使用grepawk

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-07-13
        • 2012-10-21
        • 2013-03-06
        • 2018-02-07
        • 2017-09-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多