且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在 shell 脚本中使用 read 命令逐行读取输入文件跳过最后一行

更新时间:2023-11-22 13:20:16

read 读取直到找到换行符或文件结尾,如果遇到一个非零退出代码文件结尾.所以它很可能既读取一行又返回一个非零退出代码.

read reads until it finds a newline character or the end of file, and returns a non-zero exit code if it encounters an end-of-file. So it's quite possible for it to both read a line and return a non-zero exit code.

因此,如果输入可能不被换行符终止,以下代码是不安全的:

Consequently, the following code is not safe if the input might not be terminated by a newline:

while read LINE; do
  # do something with LINE
done

因为while的主体不会在最后一行执行.

because the body of the while won't be executed on the last line.

从技术上讲,不以换行符结尾的文件不是文本文件,文本工具可能会以奇怪的方式处理此类文件.然而,我总是不愿意依赖那个解释.

Technically speaking, a file not terminated with a newline is not a text file, and text tools may fail in odd ways on such a file. However, I'm always reluctant to fall back on that explanation.

解决问题的一种方法是测试读取的内容是否为非空(-n):

One way to solve the problem is to test if what was read is non-empty (-n):

while read -r LINE || [[ -n $LINE ]]; do
  # do something with LINE
done

其他解决方案包括使用 mapfile 将文件读入数组,通过一些实用程序管道文件,该实用程序保证正确终止最后一行(grep .,对于例如,如果您不想处理空行),或者使用像 awk 这样的工具进行迭代处理(这通常是我的偏好).

Other solutions include using mapfile to read the file into an array, piping the file through some utility which is guaranteed to terminate the last line properly (grep ., for example, if you don't want to deal with blank lines), or doing the iterative processing with a tool like awk (which is usually my preference).

请注意,read 内置函数几乎肯定需要 -r;它导致 read 不重新解释输入中的 -sequences.

Note that -r is almost certainly needed in the read builtin; it causes read to not reinterpret -sequences in the input.