重击,逐行读取,将字符串除以“,”,然后存储到数组

时间:2019-06-11 08:28:29

标签: arrays bash variables while-loop

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

文件源文件。

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

脚本将输出有关回声的错误。

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

例如,当我逐一回显数组时

echo para_1[0]

它表明已存储变量。

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

${para_$i[1]}

可以这样做吗?

谢谢。

S。

2 个答案:

答案 0 :(得分:3)

有一个技巧可以使用associative arrays模拟2D数组。它效果很好,我认为是最灵活和可扩展的:

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的建立是围绕使用管道,流,fifo,重定向,进程替换等传递文件而无需保存/复制/存储文件。如果有要解析的文件,则应将其流式传输到另一个进程,解析并保存结果,而不必将整个输入存储在内存中。如果要在文件中查找某些数据,请使用grepawk

答案 1 :(得分:0)

这是一个简短的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
}