8

一段时间以来,我注意到read如果文件末尾没有“换行符”字符,则从未真正读取文件的最后一行。如果考虑到,只要文件中没有“换行符”字符,就好像它包含 0 行(这很难承认!),这是可以理解的。例如,请参见以下内容:

$ echo 'foo' > bar ; wc -l bar
1 bar

但...

$ echo -n 'bar' > foo ; wc -l foo
0 foo

那么问题来了:当用于处理尚未由我自己创建或修改的文件时,我该如何处理这种情况read,并且我不知道它们是否真的以“换行符”字符结束?

4

4 回答 4

15

read实际上,确实会将未终止的行读入分配的 var ($REPLY默认情况下)。它还在这一行返回 false,这只是意味着“文件结束”;因此,直接在经典循环中使用其返回值会while跳过最后一行。如果您稍微更改循环逻辑,则可以正确处理非换行符终止的文件,而无需事先进行清理,使用read

while read -r || [[ -n "$REPLY" ]]; do
    # your processing of $REPLY here
done < "/path/to/file"

请注意,这比依赖外部的解决方案要快得多。

Gordon Davisson 致敬以改进循环逻辑。

于 2013-01-27T12:19:35.977 回答
2

POSIX 要求文件中的任何行末尾都有一个换行符来表示它是一行。但是这个站点为您所描述的场景提供了一个解决方案。最终产品就是这个小块。

newline='
'
lastline=$(tail -n 1 file; echo x); lastline=${lastline%x}
[ "${lastline#"${lastline%?}"}" != "$newline" ] && echo >> file
# Now file is sane; do our normal processing here...
于 2013-01-27T05:16:12.330 回答
1

这或多或少是迄今为止给出的答案的组合。

它不会修改文件。

(cat file; tail -c1 file | grep -qx . && echo) | while read line
do
    ...
done
于 2013-01-27T10:32:55.353 回答
1

如果你必须使用 read,试试这个:

awk '{ print $0}' foo | while read line; do
    echo the line is $line
done

因为 awk 似乎即使没有换行符也能识别行

于 2013-01-27T05:22:48.867 回答