当bash中可能缺少尾随换行符时,同时读取两个文件
收藏

我有两个文本文件,我试图一行一行地阅读。文件的行数不一定相同,当脚本到达任一文件的结尾时,脚本应该停止读取。我想把这个保持得尽可能的“纯粹”。我找到的大多数解决方案都是这样的:

while read -r f1 && read -r f2 <&3; do
    echo "$f1"
    echo "$f2"
done < file1 3<file2

但是,如果文件的最后一行没有换行符,则此操作将失败。
如果我只读一个文件,我会做如下事情:
while IFS='' read -r line || [[ -n "$line" ]]; do
    echo "$line"
done < file1

但是,当我试图通过执行以下操作将此扩展到读取多个文件时:
while IFS='' read -r f1 || [[ -n "$f1" ]] && read -r f2 <&3 || [[ -n "$f2" ]]; do
    echo "$f1"
    echo "$f2"
done < file1 3<file2


while IFS='' read -r f1 && read -r f2 <&3 || [[ -n "$f1" || -n "$f2" ]]; do
    echo "$f1"
    echo "$f2"
done < file1 3<file2

我似乎无法正确理解逻辑,循环要么没有终止,要么没有读取最后一行就结束了。
我可以通过以下方式获得所需的行为:
while true; do
    read -r f1 <&3 || if [[ -z "$f1" ]]; then break; fi;
    read -r f2 <&4 || if [[ -z "$f2" ]]; then break; fi;
    echo "$f1"
    echo "$f2"
done 3<file1 4<file2

然而,这似乎与正常情况不符(?)
while ... read ...; do
     ... 
done

我读文件时看到的成语。
有没有更好的方法可以同时读取两个文件,这两个文件的行数可能不同,最后一行没有换行符结尾?
我阅读文件的方式有哪些潜在的缺点?


最佳答案:

通过将&&||运算符分组,可以覆盖它们的优先级:

while { IFS= read -r f1 || [[ -n "$f1" ]]; } && { IFS= read -r f2 <&3 || [[ -n "$f2" ]]; }; do

一些注意事项:在这种情况下不能使用{ }进行分组,因为这会强制其内容在子shell中运行,而子shell中的变量( )在父shell中不可用。另外,在每个read之前都需要一个;,这样shell就可以知道它不仅仅是最后一个命令的参数。最后,您需要在每个}命令之前IFS=(或等效地IFS=''),因为作为命令前缀给出的赋值仅适用于该命令。

公众号