我有一个... bash shell脚本的奇怪问题,我希望得到一些见解。
我的团队正在编写一个脚本,该脚本遍历文件中的行并检查每个行中的内容。我们遇到了一个错误,当通过将不同脚本排序在一起的自动化过程运行时,最后一行没有被看到。
用于迭代文件中的行的代码(存储在DATAFILE
中的名称是
cat "$DATAFILE" | while read line
我们可以从命令行运行脚本,它会看到文件中的每一行,包括最后一行,就好了。但是,当由自动化进程运行时(运行在相关脚本之前生成DATAFILE的脚本),最后一行从未见过。
我们更新了代码,使用以下代码迭代这些代码,并清除了问题:
for line in `cat "$DATAFILE"`
注意:DATAFILE没有在文件末尾写入新行。
我的问题是两部分......为什么最后一行不会被原始代码看到,为什么这会改变有所作为呢?
我只想到我能想出为什么最后一行不会被看到:
话虽如此,似乎如果你在shell脚本中有2个命令,那么第一个应该在脚本运行第二个命令时完全关闭。
对这些问题的任何见解,特别是第一个,都将非常感激。
答案 0 :(得分:36)
根据POSIX spec for the read command,如果“检测到文件结尾或发生错误”,它应返回非零状态。由于EOF在读取最后一个“行”时被检测到,因此它设置$line
然后返回错误状态,并且错误状态阻止循环在最后一行“行”上执行。解决方案很简单:如果读取命令成功,则执行循环;如果有任何内容被读入$line
,则执行循环。
while read line || [ -n "$line" ]; do
答案 1 :(得分:12)
cat
。 while ...;do something;done<file
就够了。for
. 使用while循环读取行时:
IFS
(否则可能会丢失缩进)。满足上述要求时,正确的while循环将如下所示:
while IFS= read -r line; do
...
done <file
并使其能够使用最终没有换行的文件(从here重新发布我的解决方案):
while IFS= read -r line || [ -n "$line" ]; do
echo "$line"
done <file
或者使用grep
和while循环:
while IFS= read -r line; do
echo "$line"
done < <(grep "" file)
答案 2 :(得分:1)
使用sed匹配文件的最后一行,如果一个文件不存在,它将附加一个换行符,并让它对该文件进行内联替换:
sed -i '' -e '$a\' file
代码来自此stackexchange link
注意:我已将空单引号添加到-i ''
,因为至少在OS X中,-i
使用-e
作为备份文件的文件扩展名。我很乐意评论原帖,但缺少50分。也许这会让我在这个帖子中获得一些,谢谢。
答案 3 :(得分:0)
我在命令行中对此进行了测试
# create dummy file. last line doesn't end with newline
printf "%i\n%i\nNo-newline-here" >testing
使用您的第一个表单(管道到while循环)进行测试
cat testing | while read line; do echo $line; done
这会错过最后一行,这是有道理的,因为read
只会获得以换行符结尾的输入。
使用第二种形式(命令替换)进行测试
for line in `cat testbed1` ; do echo $line; done
这也是最后一行
<小时/>
read
只有在被换行符终止时才会输入,这就是你错过最后一行的原因。
另一方面,在第二种形式
`cat testing`
扩展为
的形式line1\nline2\n...lineM
使用IFS将shell分隔成多个字段,所以你得到
line1 line2 line3 ... lineM
这就是为什么你仍然得到最后一行。
p / s:我不明白你是如何得到第一张表格......
答案 4 :(得分:0)
作为一种解决方法,在从文本文件中读取之前,可以将换行符附加到文件中。
echo "\n" >> $file_path
这将确保读取文件中以前的所有行。
答案 5 :(得分:0)
我有类似的问题。 我正在做一个文件的猫,将它管道排序,然后将结果传递给'while read var1 var2 var3'。 即: cat $ FILE | sort -k3 | while read Count IP Name 做 强> “do”下的工作是一个if语句,用于识别$ Name字段中的更改数据,并根据更改或没有更改确定$ Count的总和或将总计行打印到报告中。 我也遇到了无法将最后一行打印到报告中的问题。 我选择了将cat / sort重定向到一个新文件的简单权宜之计,回显新文件的换行符,然后在新文件上运行我的“while read Count IP Name”并获得成功结果。 即: cat $ FILE | sort -k3&gt;新文件 echo“\ n”&gt;&gt;新文件 cat NEWFILE | while读取计数IP名称 做 强> 有时简单,不优雅是最好的方式。