bash 在 shell 脚本中使用 read 命令逐行读取输入文件跳过最后一行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17268113/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reading input files by line using read command in shell scripting skips last line
提问by Caife
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.
我通常使用 read 命令将输入文件逐行读取到 shell 脚本中。如果未在输入文件 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
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.
输出打印所有行,包括四行。但是,当我使用cat
命令读取一行时,情况并非如此;包括最后一行在内的所有行都被打印出来,而我不必在最后添加一个额外的空行。
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.
任何人都知道为什么会发生这种情况?我创建的脚本主要由其他人运行,因此他们没有必要在每个输入文件的末尾添加额外的空行。
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).
多年来,我一直试图弄清楚这一点;如果您有任何解决方案,我将不胜感激(当然,cat
命令是一个,但我想知道 read 无法正常工作的原因)。
回答by rici
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.
read
读取直到找到换行符或文件结尾,如果遇到文件结尾,则返回非零退出代码。所以它很可能既读取一行又返回一个非零的退出代码。
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
because the body of the while
won't be executed on the last line.
因为 的主体while
不会在最后一行执行。
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.
从技术上讲,不以换行符结尾的文件不是文本文件,文本工具可能会以奇怪的方式处理此类文件。然而,我总是不愿意回到那个解释。
One way to solve the problem is to test if what was read is non-empty (-n
):
解决问题的一种方法是测试读取的内容是否为非空 ( -n
):
while read -r LINE || [[ -n $LINE ]]; do
# do something with LINE
done
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).
其他解决方案包括使用mapfile
将文件读入数组,通过一些实用程序管道文件,该实用程序保证正确终止最后一行(grep .
例如,如果您不想处理空行),或进行迭代处理使用类似的工具awk
(这通常是我的偏好)。
Note that -r
is almost certainly needed in the read
builtin; it causes read
to not reinterpret \
-sequences in the input.
请注意,-r
几乎可以肯定在read
内置函数中需要它;它导致read
不重新解释\
输入中的序列。
回答by Steven Penny
DONE=false
until $DONE
do
read line || DONE=true
echo $line
done < blah.txt
回答by Jahid
Use while loop like this:
像这样使用while循环:
while IFS= read -r line || [ -n "$line" ]; do
echo "$line"
done <file
Or using grep
with while loop:
或grep
与 while 循环一起使用:
while IFS= read -r line; do
echo "$line"
done < <(grep "" file)
Using grep .
instead of grep ""
will skip the empty lines.
使用grep .
而不是grep ""
将跳过空行。
Note:
笔记:
Using
IFS=
keeps any line indentation intact.File without a newline at the end isn't a standard unix text file.
使用
IFS=
可以保持任何行缩进完好无损。最后没有换行符的文件不是标准的 unix 文本文件。
回答by sandino
One line answer:
一行回答:
IFS=$'\n'; for line in $(cat file.txt); do echo "$line" ; done
回答by Aniket Thakur
Below code with Redirected "while-read" loop works fine for me
下面带有重定向“while-read”循环的代码对我来说很好用
while read LINE
do
let count++
echo "$count $LINE"
done < $FILENAME
echo -e "\nTotal $count Lines read"