while read 循环在第一行之后停止,即使它没有从 stdin 读取

while read 循环在第一行之后停止,即使它没有从 stdin 读取

我有一个名为test包含的文件

test
test

我正在运行这个命令

while read line
do
echo "$line"
done </tmp/test

这应该输出“test”两次,但它只输出一次。使用while IFS= read -r line不会改变任何东西。解决这个问题的方法是输出第三个空行,但无论如何它都应该有效。

答案1

尝试:

while IFS='' read -r line || [ "$line" ]

是的,它正在从标准输入(stdin)读取,<test重定向到stdin。

可能发生的情况是 read 被设计用于处理文本文件。正确的文本文件必须以换行符结尾

做一个换行符上的文件结尾结果非常快

[ -n "$(tail -c1 file)" ] && printf '\n' >>file 

但是,如果您无法编辑文件以添加换行符(如果丢失),则解决方案是(另外)测试是否读取了某些内容:

while read line || [ "$line" ]

如果读取失败(到达文件末尾而不读取换行符(默认情况下))但读取了某些内容(in "$line"),这将使循环执行。

对于以换行符结尾或不以换行符结尾的文件,这都可以正常工作。

不,aIFS='' read不会(直接)影响最后一行的读取,事实上,IFS=''(与默认的 IFS 相比)[A]空格、制表符、换行符)只会影响拆分为一些变量(除了影响前导和/或尾随空白的删除(如果 IFS 仅包含空白)[b]))。由于只有一个变量 ( "$line"),因此无需执行拆分。

读取选项-d(自 2.04 起在 bash 中)也无济于事。没有特定的“文件结束”字符来匹配(最后一个字节可以是任何字符)。

剩下的唯一选择是:

  • 修复文件以使其成为正确的文本文件
  • 测试是否有任何内容被读入变量line

那么,正确的脚本将是:

#!/bin/bash
while IFS='' read -r line || [ "$line" ]
do
    printf '%s\n' "$line"
done <test

IFS='' 用于避免 IFS 的不常见值出现问题。


[一][二]当然,如果 IFS 可能有任何价值,那么许多其他字符可能会被删除。尝试(对于以“x”结尾的值)

printf "test\ntesx\ntest" | while IFS="x" read -r line || [ "$line" ]; do echo "$line"; done

不,zsh 做了一些不同的事情。

相关内容