在文件末尾添加行时,文本有时不会写入新行

在文件末尾添加行时,文本有时不会写入新行

在某些情况下,当我们想要将新行追加到文件时,我们会看到实际上我们追加的新行已插入到最后一行的末尾

例如,这里是附加之前的文件:

more /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

现在我们附加:

echo "182.2.3.4 host_1" >>/etc/hosts

我们得到:

more /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6182.2.3.4 host_1

也许最简单的解决方案是:

echo  >> /etc/hosts

但我很乐意得到一些其他的解决方案。

答案1

这是因为原始文件的最后一行末尾没有换行符。echo "182.2.3.4 host_1"不在开头添加一(但在末尾添加一, after ...host_1),因此生成的文件没有。

因为这样的问题,而且严格来说,该标准需要一个“行”以换行符结尾,您应该确保始终将其放在那里。一些实用程序可能会在没有最后一个换行符的情况下给出意外的行为(例如,wc -l计算换行符,因此不会将此类行算作一行;read如果内置函数没有看到换行符,则返回错误状态)。有些编辑总是添加它,有些则不添加。在没有的情况下,请确保在最后一行后按 Enter 键,或者查看是否可以将光标移动到其下方的“空行”以确保换行符在那里。

类似的文件可以用例如修复

perl -i  -pe '$_ .= "\n" unless /\n$/' file-maybe-without-nl.txt

如果尾随换行符已经存在,则应将其保留原样。 (awk 1 < file.txt > fixed.txt似乎也有效,但 awk 没有标准的就地编辑功能。sed有,但我不知道如何使用它。)

当然,您也可以无条件地添加换行符,例如echo >> /etc/hosts, 或echo -e '\n182.2.3.4 host_1' >> /etc/hosts,但是如果文件在添加之前格式正确,则会在中间添加虚假的空行。

在不必读取整行的情况下检查最终换行符的一种方法是使用tail -n1tail -c1获取最后一行(或行片段)或仅最后一个字符。然后

[ "$(tail -c1 "$f")" = "" ] || echo >> "$f"

如果需要的话可以用来添加它。 (这依赖于命令替换吃掉任何换行符,所以如果换行符它的扩展是空的)或者使用read(如果没有看到换行符,则返回错误状态):

tail -c1 file | read -r tmp || echo >> file

(后一个命令的想法tail和整个命令借鉴自此处的博客文章:https://backreference.org/2010/05/23/sanitizing-files-with-no-trailing-newline/

请注意,回车符 (CR) 与在类 Unix 系统上用作行终止符的换行符/换行符 (LF) 不同。 (CR+LF 在 DOS 和 Windows 上用作行终止符。)

相关内容