20

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

#!/bin/sh

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

因此,如果输入文件读取类似 -

One 
Two
Three
Four

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

One
Two
Three

现在,如果我在四之后留下一个额外的空行,例如,

One 
Two
Three
Four
//blank line

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

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

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

4

5 回答 5

21

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

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

while read LINE; do
  # do something with LINE
done

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

从技术上讲,不以换行符结尾的文件不是文本文件,文本工具可能会以奇怪的方式在此类文件上失败。但是,我总是不愿依赖这种解释。

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

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

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

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

于 2013-06-24T04:46:36.407 回答
8
DONE=false
until $DONE
do
  read line || DONE=true
  echo $line
done < blah.txt

如果文件末尾没有换行符,如何使用`while read`(Bash)读取文件中的最后一行?

于 2013-06-24T04:46:07.340 回答
7

像这样使用 while 循环:

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

或使用grepwhile 循环:

while IFS= read -r line; do
  echo "$line"
done < <(grep "" file)

使用grep .而不是grep ""将跳过空行。

笔记:

  1. 使用IFS=使任何行缩进保持不变。

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

  3. 不要阅读与for

  4. 最后没有换行符的文件不是标准的 unix 文本文件。

于 2015-07-14T04:10:56.367 回答
4

一行回复:

IFS=$'\n'; for line in $(cat file.txt); do echo "$line" ; done
于 2014-05-07T19:56:52.467 回答
0

下面带有重定向的“while-read”循环的代码对我来说很好

while read LINE
do
      let count++
      echo "$count $LINE"

done < $FILENAME

echo -e "\nTotal $count Lines read"
于 2014-05-19T08:33:32.927 回答