为什么这个“while”循环无法识别最后一行?

为什么这个“while”循环无法识别最后一行?

我们使用以下脚本:

more test.sh
#!/bin/bash

while read -r line
do

echo $line

done < /tmp/file

这是文件:

kafka-broker,log.retention.hours,12
kafka-broker,default.replication.factor,2
fefolp-defaults,fefolp.history.fs.cleaner.interval,1d
fefolp-defaults,fefolp.history.fs.cleaner.maxAge,2d
fefolp-env,fefolp_daemon_memory,10000
blo-site,blo.nodemanager.localizer.cache.target-size-mb,10240
blo-site,blo.nodemanager.localizer.cache.cleanup.interval-ms,300000
ams-env,metrics_collector_heapsize,512
fefolp,hbase_master_heapsize,1408
fefolp,hbase_regionserver_heapsize,512
fefolp,hbase_master_xmn_size,192
core-site,blolp.proxyuser.ambari.hosts,*
core-site,Hadoop.proxyuser.root.groups,*
core-site,Hadoop.proxyuser.root.hosts,*
blo-site,blo.scheduler.minimum-allocation-mb,1024
blolp-env,fefolp_heapsize,4096

备注 - 最后一行之后 - 没有空格!

但该脚本仅打印这些行(最后一行除外):

./test.sh
kafka-broker,log.retention.hours,12
kafka-broker,default.replication.factor,2
fefolp-defaults,fefolp.history.fs.cleaner.interval,1d
fefolp-defaults,fefolp.history.fs.cleaner.maxAge,2d
fefolp-env,fefolp_daemon_memory,10000
blo-site,blo.nodemanager.localizer.cache.target-size-mb,140
blo-site,blo.nodemanager.localizer.cache.cleanup.interval-ms,300
ams-env,metrics_collector_heapsize,51
fefolp,hbase_master_heapsize,1408
fefolp,hbase_regionserver_heapsize,542
fefolp,hbase_master_xmn_size,19
core-site,blolp.proxyuser.ambari.hosts,*
core-site,Hadoop.proxyuser.root.groups,*
core-site,Hadoop.proxyuser.root.hosts,*
blo-site,blo.scheduler.minimum-allocation-mb,1024

为什么会发生这种情况?

答案1

您的输入文本的最后一行包含不完整的行。最后一行不以换行符结束。

while IFS= read -r line || [ -n "$line" ]; do
    printf '%s\n' "$line"
done <file

上面的循环将从调用的文件中读取未修改的行(不删除空格或解释反斜杠控制序列)file并将其打印到标准输出。

不完整的读取read行将失败,但$line仍包含数据。额外的-n测试将检测到这一点,以便允许循环体输出不完整的行。在之后的迭代中,read将再次失败并$line为空字符串,从而终止循环。


假设它们在 shell 中不包含 NUL 字符,并且zsh假设它们不包含不构成yashshell 中有效字符一部分的字节序列,如果输入是有效文本,则这两种情况都不会发生,尽管缺少最后一行的行分隔符已经使其成为无效文本。

答案2

while read 循环的输入必须如下完成:

cat /tmp/file | { cat ; echo ; } | while read -r line; do echo $line;  done

这将处理所有行,包括最后一行。

来源:我的开源项目https://sourceforge.net/projects/command-output-to-html-table/

答案3

下列的您的输入文本的最后一行包含不完整的行。最后一行不以换行符结束。保持循环不变,只需确保变量行有返回即可。

while read -r i
do
#
line="$(echo "$i"| sed 's/$/@/'| tr '\n' '@'|sed 's/@@/@/' |tr '@' '\n')"
#
echo $line
#
done < /tmp/file

您可以将 更改@为您喜欢的任何内容。

相关内容