我正在学习 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
这将创建两个数组a1
并a2
包含制表符分隔元素每行的,并循环到该行的长度file1
(忽略其他文件中的任何额外项目)。
zip
假设文件格式良好并且列数在相应的行上匹配,则最好的通用近似类似while read a b ... done < <(paste <(printf '%s\n' $(<file1)) <(printf '%s\n' $(<file2)))
,这绝对是令人厌恶的。
也就是说,shell 脚本不是进行此类处理的良好机制,而 awk - 或者甚至更好,一种合适的语言 - 会比这更合适并且更不脆弱。
我认为您可以从上面的脚本中看到,这实现起来过于复杂,非常脆弱,并且难以遵循,因为该语言不是为此而设计的。这些脚本是更多的比实现相同目标的其他方法更具可读性,这并没有说明太多。