bash 如果在使用 read 时没有以换行符 (\n) 终止,则尊重最后一行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14544636/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 04:22:17  来源:igfitidea点击:

Respect last line if it's not terminated with a new line char (\n) when using read

bashshellbuilt-in

提问by michaelmeyer

I have noticed for a while that readnever actually reads the last line of a file if there is not, at the end of it, a "newline" character. This is understandable if one consider that, as long as there is not a "newline" character in a file, it is as if it contained 0 line (which is quite difficult to admit !). See, for example, the following:

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

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

But...

但...

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

The question is then: how can I handle such situations when using readto process files which have not been created or modified by myself, and about which I don't know if they actually end up with a "newline" character ?

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

回答by kopischke

readdoes, in fact, read an unterminated line into the assigned var ($REPLYby default). It also returns false on such a line, which just means ‘end of file'; directly using its return value in the classic whileloop thus skips that one last line. If you change the loop logic slightly, you can process non-new line terminated files correctly, without need for prior sanitisation, with read:

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

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

Note this is much faster than solutions relying on externals.

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

Hat tip to Gordon Davissonfor improving the loop logic.

帽尖到戈登戴维森用于改善循环逻辑。

回答by JakeGould

POSIX requires any line in a file have a newline character at the end to denote it is a line. But this siteoffers a solution to exactly the scenario you are describing. Final product is this chunklet.

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...

回答by EJK

If you must use read, try this:

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

awk '{ print 
(cat file; tail -c1 file | grep -qx . && echo) | while read line
do
    ...
done
}' foo | while read line; do echo the line is $line done

as awk seems to recognize lines even without the newline char

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

回答by user123444555621

This is more or less a combination of the answers given so far.

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

It does not modify the files in place.

它不会就地修改文件。

##代码##