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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 23:52:26  来源:igfitidea点击:

Reading input files by line using read command in shell scripting skips last line

bashparsingshellfile-io

提问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 catcommand; 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 catcommand is one, but I'd like to know the reason behind read not working as well).

多年来,我一直试图弄清楚这一点;如果您有任何解决方案,我将不胜感激(当然,cat命令是一个,但我想知道 read 无法正常工作的原因)。

回答by rici

readreads 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 whilewon'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 mapfileto 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 -ris almost certainly needed in the readbuiltin; it causes readto not reinterpret \-sequences in the input.

请注意,-r几乎可以肯定在read内置函数中需要它;它导致read不重新解释\输入中的序列。

回答by Jahid

Use while loop like this:

像这样使用while循环:

while IFS= read -r line || [ -n "$line" ]; do
  echo "$line"
done <file

Or using grepwith 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:

笔记:

  1. Using IFS=keeps any line indentation intact.

  2. You should almost always use the -r option with read.

  3. Don't read lines with for

  4. File without a newline at the end isn't a standard unix text file.

  1. 使用IFS=可以保持任何行缩进完好无损。

  2. 您几乎应该总是将 -r 选项与 read 一起使用。

  3. 不要阅读行 for

  4. 最后没有换行符的文件不是标准的 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"