从bash中的文本文件中读取多行

Eri*_*ric 5 shell bash text-processing

当我编写 shell 脚本时,我所做的大部分工作是将其他模块的 I/O 包装在 python、matlab 等中。为此,我通常使用文本文件或类似性质的输入/输出路径。我知道从我可以使用的一个文件中读取一行,

for file in $(cat $1);
do
    code using $file
done
Run Code Online (Sandbox Code Playgroud)

但是如果我想使用两个文件中的等效行做某事怎么办?类似于等效的Java:

while((line1 = file1.readLine()) != null) {
    line2 = file2.readLine();
    //do something with both lines...
}
Run Code Online (Sandbox Code Playgroud)

在 bash 中执行此操作的标准方法是什么?

Joh*_*024 5

exec 3<file1
exec 4<file2
while read line1 <&3 && read line2 <&4
do
        echo "line1=$line1 and line2=$line2"
done
exec 3<&-
exec 4<&-
Run Code Online (Sandbox Code Playgroud)

讨论

  • 在上面,从输入行中去除了前导和尾随空白。如果要保留此空格,请替换read …IFS= read …

  • 在上面,输入中的反斜杠将被解释为转义字符。如果您不想要那样,请替换read …read -r …

  • read line1 <&3line1从文件描述符 3读取。这也可以等效地写为read -u3 line1.

  • 诸如此类的语句for file in $(cat $1);有一些您应该了解的问题。shell 会将分词路径名扩展应用到文件的内容,除非您预料到这一点,否则可能会导致各种错误。

选择

while read line1 <&3 && read line2 <&4
do
        echo "line1=$line1 and line2=$line2"
done 3<file1 4<file2
Run Code Online (Sandbox Code Playgroud)


Gil*_*il' 5

要迭代文件的行:

\n\n
while IFS= read -r line; do\n  echo "read $line"\ndone <input-file\n
Run Code Online (Sandbox Code Playgroud)\n\n

要迭代多个文件,请在不同的文件描述符上打开它们(请参阅何时使用附加文件描述符?)。

\n\n
while IFS= read -r line1 <&8 || IFS= read -r line2 <&9; do\n  echo "read \'$line1\' from file 1 and \'$line2\' from file 2"\ndone 8<input-file1 9<input-file2\n
Run Code Online (Sandbox Code Playgroud)\n\n

使用read <&8 || read <&9空行完成最短的文件以匹配最长的文件。要在到达任一文件末尾后立即退出,请使用&&而不是||. 如果要检测所有情况,请单独检查返回码。

\n\n
{\n  while\n    IFS= read -r line1 <&8; empty1=$?\n    IFS= read -r line2 <&9; empty2=$?\n    [ "$empty1" -ne 0 ] && [ "$empty2" -ne 0 ]\n  do\n    echo "read \'$line1\' from file 1 and \'$line2\' from file 2"\n  done\n  if [ "$empty1" -ne 0 ]; then\n    echo "Finishing processing file 1"\n    \xe2\x80\xa6\n  fi\n  if [ "$empty2" -ne 0 ]; then\n    echo "Finishing processing file 2"\n    \xe2\x80\xa6\n  fi\n} 8<input-file1 9<input-file2\n
Run Code Online (Sandbox Code Playgroud)\n\n

或者,您可以将两个文件连接在一起。该paste命令对此很方便。默认情况下,它通过制表符分隔行(通过-d以选择不同的分隔符)并用空行完成文件。如果文件不包含制表符,则会明确界定输入行。

\n\n
tab=$(printf \\\\t)\npaste input-file1 input-file2 |\nwhile IFS=$tab read -r line1 line2; do \xe2\x80\xa6 done\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,shell 进行文本处理的速度不是很快。更专业的工具最适合中型到大型输入。预处理paste可以方便地将两个文件压缩在一起以进行任何后处理。如果您需要更多地控制何时读取行, awk 可以使用其getline命令来完成此操作(类似于 shell 的read)。

\n