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 中执行此操作的标准方法是什么?
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)
要迭代文件的行:
\n\nwhile IFS= read -r line; do\n echo "read $line"\ndone <input-file\nRun Code Online (Sandbox Code Playgroud)\n\n要迭代多个文件,请在不同的文件描述符上打开它们(请参阅何时使用附加文件描述符?)。
\n\nwhile 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\nRun Code Online (Sandbox Code Playgroud)\n\n使用read <&8 || read <&9空行完成最短的文件以匹配最长的文件。要在到达任一文件末尾后立即退出,请使用&&而不是||. 如果要检测所有情况,请单独检查返回码。
{\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\nRun Code Online (Sandbox Code Playgroud)\n\n或者,您可以将两个文件连接在一起。该paste命令对此很方便。默认情况下,它通过制表符分隔行(通过-d以选择不同的分隔符)并用空行完成文件。如果文件不包含制表符,则会明确界定输入行。
tab=$(printf \\\\t)\npaste input-file1 input-file2 |\nwhile IFS=$tab read -r line1 line2; do \xe2\x80\xa6 done\nRun Code Online (Sandbox Code Playgroud)\n\n请注意,shell 进行文本处理的速度不是很快。更专业的工具最适合中型到大型输入。预处理paste可以方便地将两个文件压缩在一起以进行任何后处理。如果您需要更多地控制何时读取行, awk 可以使用其getline命令来完成此操作(类似于 shell 的read)。