linux脚本取最后一行,Shell脚本读取最后一行丢失

C标准表示文本文件必须以换行符结束,否则可能无法正确读取最后一行换行符后的数据。ISO / IEC 9899:2011§7.21.2流

文本流是由行组成的有序字符序列,每行由零个或多个字符加上终止的换行符组成。最后一行是否需要终止换行符是实现定义的。可能必须在输入和输出上添加,更改或删除字符,以符合在主机环境中表示文本的不同约定。因此,流中的字符与外部表示中的字符之间不需要一一对应。从文本流读入的数据必须与之前写入该流的数据相等,只有在以下情况下:数据仅包含打印字符,控制字符包含水平制表符和新行; 空格字符前面不会有任何换行符; 最后一个字符是换行符。在读入时是否出现在换行符之前立即写出的空格字符是实现定义的。

我不会在文件末尾意外丢失换行符导致bash(或任何Unix shell)出现问题,但这似乎是可重现的问题($是此输出中的提示):$ echo xxx\\c

xxx$ { echo abc; echo def; echo ghi; echo xxx\\c; } > y

$ cat y

abc

def

ghi

xxx$

$ while read line; do echo $line; done 

abc

def

ghi

$ bash -c 'while read line; do echo $line; done 

def

ghi

$ ksh -c 'while read line; do echo $line; done 

def

ghi

$ zsh -c 'while read line; do echo $line; done 

def

ghi

$ for line in $(

def

ghi

xxx

$ for line in $(cat y); do echo $line; done   # UUOC Award pendingabc

def

ghi

xxx

$

它也不仅限于bash- Korn shell(ksh),并且zsh行为也是如此。我活着,我学习; 谢谢你提出这个问题。

如上面的代码所示,该cat命令读取整个文件。该for line in `cat $DATAFILE`技术收集所有输出并用一个空格替换任意的空白序列(我得出结论,文件中的每一行都不包含空格)。

在Mac OS X 10.7.5上测试。

POSIX说什么?

POSIX read命令规范说:读取实用程序应从标准输入读取一行。

默认情况下,除非-r指定了该选项,否则将充当转义字符。未转义的应保留后续字符的文字值,但除外。如果跟在之后,则读取实用程序应将此解释为行继续。在将输入拆分为字段之前,应删除 。将输入拆分为字段后,应删除所有其他未转义的字符。

如果标准输入是终端设备并且调用shell是交互式的,则当读取以 结尾的输入行时,读取将提示继续行,除非-r指定了该选项。

终止 (如果有的话)应从输入中删除,结果应分成字段,如shell中的参数扩展结果(参见Field Splitting); [...]

请注意'(如果有的话')(重点在引用中添加)!在我看来,如果没有新行,它仍然应该读取结果。另一方面,它还说:STDIN

标准输入应为文本文件。

然后你回到关于不以换行结尾的文件是否是文本文件的争论。

但是,同一页面文件的基本原理:虽然标准输入必须是文本文件,因此总是以结束(除非它是空文件),但是在-r不使用该选项时继续行的处理可能导致输入不以一个。如果输入文件的最后一行以结尾,则会发生这种情况。出于这个原因,在“终止(如果有的话)中使用”if any“将从描述中的输入中删除”。放宽标准输入作为文本文件的要求并不放松。

该基本原理必须意味着文本文件应该以换行符结束。

POSIX文本文件的定义是:包含组织为零行或多行的字符的文件。这些行不包含NUL字符,长度不能超过{LINE_MAX}个字节,包括字符。尽管POSIX.1-2008不区分文本文件和二进制文件(请参阅ISO C标准),但许多实用程序在操作文本文件时仅产生可预测或有意义的输出。具有此类限制的标准实用程序始终在其STDIN或INPUT FILES部分中指定“文本文件”。

这并没有直接规定“以结尾”,而是遵循C标准。

“无终端换行”问题的解决方案

注意戈登戴维森的回答。一个简单的测试表明他的观察是准确的:$ while read line; do echo $line; done 

abc

def

ghi

xxx

$

因此,他的技术:while read line || [ -n "$line" ]; do echo $line; done 

要么:cat y | while read line || [ -n "$line" ]; do echo $line; done

将适用于最后没有换行的文件(至少在我的机器上)。

我仍然惊讶地发现shell丢弃了最后一个段(它不能被称为一行,因为它不以换行符结束),但POSIX中可能有足够的理由这样做。显然,最好确保您的文本文件确实是以换行符结尾的文本文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值