![while read 循环在第一行之后停止,即使它没有从 stdin 读取](https://linux22.com/image/97983/while%20read%20%E5%BE%AA%E7%8E%AF%E5%9C%A8%E7%AC%AC%E4%B8%80%E8%A1%8C%E4%B9%8B%E5%90%8E%E5%81%9C%E6%AD%A2%EF%BC%8C%E5%8D%B3%E4%BD%BF%E5%AE%83%E6%B2%A1%E6%9C%89%E4%BB%8E%20stdin%20%E8%AF%BB%E5%8F%96.png)
我有一个名为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 做了一些不同的事情。