在 shell 脚本中使用 read 命令逐行读取输入文件跳过最后一行 [英] Reading input files by line using read command in shell scripting skips last line

查看:134
本文介绍了在 shell 脚本中使用 read 命令逐行读取输入文件跳过最后一行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我通常使用read命令将输入​​文件逐行读取到shell脚本中.如果未在输入文件 blah.txt 的最后一行末尾插入新行,则如下示例代码会产生错误结果.

I usually use the read command to read an input file to the shell script line by line. An example code such as the one below yields a wrong result if a new line isn't inserted at the end of the last line in the input file, blah.txt.

#!/bin/sh

while read line
do
echo $line
done <blah.txt

所以如果输入文件读起来像 -

So if the input file reads something like -

One 
Two
Three
Four

并且我在四之后没有回车,脚本无法读取最后一行,并打印

and I do not hit return after Four, the script fails to read the last line, and prints

One
Two
Three

现在如果我在四之后多留一个空行,比如,

Now if I leave an extra blank line after Four, like,

One 
Two
Three
Four
//blank line

输出打印所有行,包括四行.但是,当我使用 cat 命令读取一行时,情况并非如此;包括最后一行在内的所有行都会打印出来,而我不必在末尾添加一个额外的空行.

the output prints all the lines, including Four. However, this is not the case when I read a line using the cat command; all lines including the last get printed without me having to add an extra blank line at the end.

有人知道为什么会发生这种情况吗?我创建的脚本主要由其他人运行,因此他们没有必要在每个输入文件的末尾添加额外的空行.

Anyone has ideas on why this happens? The scripts I create will mostly be run by others, so it isn't necessary they're going to add an extra blank line at the end of every input file.

多年来我一直在努力解决这个问题;如果您有任何解决方案,我将不胜感激(当然,cat 命令是其中之一,但我想知道 read 无法正常工作的原因).

I've been trying to figure this out for ages; I'd appreciate it if you have any solutions(of course, the cat command is one, but I'd like to know the reason behind read not working as well).

推荐答案

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.

这篇关于在 shell 脚本中使用 read 命令逐行读取输入文件跳过最后一行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆