如何找到末尾没有空行的文件?

如何找到末尾没有空行的文件?

我在当前目录的子目录中有一些文件,它们的末尾可能有换行符,也可能没有换行符;如何找到末尾没有换行符的文件?

我试过这个:

find . -name '*.styl' | while read file; do
    awk 'END{print}' $file | grep -E '^$' > /dev/null || echo $file;
done

但它不起作用。 awk 'END{print}' $file打印空新行之前的行,与 相同tail -n 1 $file

答案1

澄清一下,LF(又名\n或换行符)字符是行分隔符,它不是行分隔符。除非以换行符结束一行,否则该行并未结束。仅包含的文件a\nb不是有效的文本文件,因为它包含最后一行之后的字符。对于仅包含a.a\n包含一个非空行的文件。

因此,以至少一个空行结尾的文件以两个换行符结尾或包含一个换行符。

如果:

 tail -c 2 file | od -An -vtc

输出\n\n \n,则文件至少包含一个尾随空行。如果它什么都不输出,那么这是一个空文件,如果它输出<anything-but-\0> \n,那么它以非空行结束。除此之外,它不是一个文本文件。

现在,要使用它来查找以空行结尾的文件,这是有效的(特别是对于大文件),因为它只读取文件的最后两个字节,但首先输出不容易以编程方式解析,特别是考虑到它从一个实现到下一个实现并不一致od,我们需要为每个文件运行一个tail又一个。od

find . -type f -size +0 -exec gawk '
  ENDFILE{if ($0 == "") print FILENAME}' {} +

(查找以空行结尾的文件)将运行尽可能少的命令,但这意味着读取所有文件的完整内容。

理想情况下,您需要一个能够自行读取文件末尾的 shell。

zsh

zmodload zsh/system
for f (**/*(D.L+0)) {
  {
    sysseek -w end -2
    sysread
    [[ $REPLY = $'\n' || $REPLY = $'\n\n' ]] && print -r -- $f
  } < $f
}

答案2

使用gnu sed和 类似的外壳zsh(或bash使用shopt -s globstar):

sed -ns '${/./F}' ./**/*.styl

这会检查每个文件的最后一行是否不为空,如果是,则打印文件名。
如果您想要相反的结果(如果最后一行为空则打印文件名)只需替换/.//^$/

答案3

正确终止的文本文件最后一行为空,以两个\n.

那么,我们期望tail -c2必须等于$'\n\n'

遗憾的是命令扩展删除了尾随的新行。我们需要进行一些调整。

f=filename
nl='
'
t=$(tail -c2 $f; printf x)  # capture the last two characters.
r="${nl}${nl}$"                 # regex for: "ends in two newlines".
[[ ${t%x} =~ $r ]] &&  echo "file $f ends in an empty line"

我们甚至可以扩展一下来检查哪些文件没有尾随新行:

nl='
'
nl=$'\n'
find . -type f -name '*.styl' | while read f; do
    t=$(tail -c2 $f; printf x); r1="${nl}$"; r2="${nl}${r1}"
    [[ ${t%x} =~ $r1 ]] || echo "file $f is missing a trailing newline"
    [[ ${t%x} =~ $r2 ]] && echo "$f"
done

$'\r\n请注意,如果需要,换行符可以更改为类似的内容。
在这种情况下,也更改tail -c2tail -c4.

相关内容