使用 for 循环遍历两个文件并评估索引

使用 for 循环遍历两个文件并评估索引

我正在学习 bash shell 脚本,并且正在寻找纯粹的 bash 方式而不是 awk 等。

我正在尝试使用 for 循环来遍历在终端中作为参数提交的两个文件的内容,以便我可以根据信息编写表达式。

文件内容用制表符分隔。这些文件没有扩展名。以下是我要评估的文件信息类型的示例:

$cat file1
1     2     3
40    50    60

$cat file2
10     20     30
40     50     60

这是我写的代码:

read line1 < "file1"
read line2 < "file2"

difference=0

#I can see the contents of file1 with the below code and by changing the code
#slightly I can see the contents of file2 as well using the following code:

for index1 in $line1
do
echo "The contents of index1 are: $index1"
done

#But I am trying to do something like this which isn't working:
for index1 in $line1, index2 in $line2
do
difference=$(expr $index1 - $index2)
echo $difference
done

答案1

这绝对是可能的,但并不令人愉快。事实上,你会想以不同的方式处理事情。

对于这些特定文件和此任务,此脚本可能是最简单的,并且使用单个while循环而不是任何循环for

exec 3<file2
while read a1 a2 a3 && read b1 b2 b3 <&3
do
    echo $((a1 - b1))
    echo $((a2 - b2))
    echo $((a3 - b3))
done < file1

每个文件都有固定的三列结构,并且一次读取所有文件。file2在文件描述符 3 上打开(exec 3<file2)这样你就可以独立地阅读它file1:你所写的内容将打开文件并读取第一的每次都只需要排队。这些read命令将第一个单词放入x1,第二个单词放入x2,并将该行的其余部分放入`x3。

没有内置的或相当简单的方法可以将两个列表“压缩”在一起,或者编写并行的 for 循环。除了简单数组或文字单词列表之外的任何内容的 for 循环都很难甚至不可能,并且构建正确的数组比以其他方式执行任务需要更多工作。


如果列数可变,这会更棘手,但我们可以使用mapfile从行创建数组,然后使用常规数组处理C型for循环对于每行:

while read line1 && read line2 <&3
do
    mapfile -d $'\t' a1 <<<"$line1"
    mapfile -d $'\t' a2 <<<"$line2"
    for ((i=0; i<${#a1[@]}; i++))
    do
        echo $((a1[i] - a2[i]))
    done
done <file1

这将创建两个数组a1a2包含制表符分隔元素每行的,并循环到该行的长度file1(忽略其他文件中的任何额外项目)。

zip假设文件格式良好并且列数在相应的行上匹配,则最好的通用近似类似while read a b ... done < <(paste <(printf '%s\n' $(<file1)) <(printf '%s\n' $(<file2))),这绝对是令人厌恶的。


也就是说,shell 脚本不是进行此类处理的良好机制,而 awk - 或者甚至更好,一种合适的语言 - 会比这更合适并且更不脆弱。

我认为您可以从上面的脚本中看到,这实现起来过于复杂,非常脆弱,并且难以遵循,因为该语言不是为此而设计的。这些脚本是更多的比实现相同目标的其他方法更具可读性,这并没有说明太多。

相关内容