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

Mat*_*ens 48 bash newline eof

假设我有以下Bash脚本:

while read SCRIPT_SOURCE_LINE; do
  echo "$SCRIPT_SOURCE_LINE"
done
Run Code Online (Sandbox Code Playgroud)

我注意到,对于最后没有换行的文件,这将有效地跳过最后一行.

我一直在寻找解决方案,并发现了这个:

当读取到达文件结尾而不是行尾时,它会读入数据并将其分配给变量,但它会以非零状态退出.如果你的循环是"在阅读时构建的;做的事情;完成

因此,不是直接测试读取退出状态,而是测试一个标志,并让read命令在循环体内设置该标志.这样,无论读取退出状态如何,整个循环体都会运行,因为读取只是循环中的命令列表之一,就像其他任何循环一样,而不是决定循环是否会运行的决定因素.

DONE=false
until $DONE ;do
read || DONE=true
# process $REPLY here
done < /path/to/file.in
Run Code Online (Sandbox Code Playgroud)

如何重写此解决方案,使其行为与while我之前的循环完全相同,即没有硬编码输入文件的位置?

Ada*_*zak 39

我使用以下构造:

while IFS= read -r LINE || [[ -n "$LINE" ]]; do
    echo "$LINE"
done
Run Code Online (Sandbox Code Playgroud)

除了输入中的空字符外,它几乎可以使用任何东西:

  • 以空行开头或结尾的文件
  • 以空格开头或结尾的行
  • 没有终止换行符的文件

  • 您不需要在IFS中包含换行符; 你可以简单地将它设置为空字符串.另外,为了使这个POSIX兼容(目前它仅适用于bash,而不是`/ bin/sh`),请执行`IFS =''读取-r LINE || [-n"$ LINE"]` (4认同)
  • 请注意,如果没有,则会在EOF处添加额外的换行符. (3认同)

net*_*der 14

在你的第一个例子中,我假设你是从stdin读取的.要对第二个代码块执行相同操作,您只需删除重定向并回显$ REPLY:

DONE=false
until $DONE ;do
read || DONE=true
echo $REPLY
done
Run Code Online (Sandbox Code Playgroud)

  • 为了避免处理额外的(空)行,如果*是*最终换行,请在包含`read`的行之后添加:`[[!$ REPLY]] &&继续` (3认同)

Jah*_*hid 5

使用grepwhile循环:

while IFS= read -r line; do
  echo "$line"
done < <(grep "" file)
Run Code Online (Sandbox Code Playgroud)

使用grep .代替grep ""将跳过空行。

注意:

  1. 使用IFS=可使所有行缩进保持不变。

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

  3. 结尾没有换行符的文件不是标准的UNIX文本文件。


pra*_*397 5

尝试使用GNU Coreutils,teecat等,而不是read 。

来自标准输入

readvalue=$(tee)
echo $readvalue
Run Code Online (Sandbox Code Playgroud)

从文件

readvalue=$(cat filename)
echo $readvalue
Run Code Online (Sandbox Code Playgroud)