如何列出不以换行符结尾的普通文本(.txt
)文件名?
例如:列出(输出)此文件名:
$ cat a.txt
asdfasdlsad4randomcharsf
asdfasdfaasdf43randomcharssdf
$
并且不列出(输出)此文件名:
$ cat b.txt
asdfasdlsad4randomcharsf
asdfasdfaasdf43randomcharssdf
$
答案 0 :(得分:23)
使用pcregrep,一个perp兼容的正则表达式版本的grep,它支持使用-M标志的多行模式,如果最后一行有换行符,可用于匹配(或不匹配):
pcregrep -LMr '\n$' .
在上面的示例中,我们要在当前目录(-r
)中递归搜索(.
),列出不匹配(-L
)多行的文件({ {1}})在文件末尾查找换行符的正则表达式(-M
)
将'\n$'
更改为-L
会列出 中包含换行符的文件。
-l
包在MacOS上安装 pcregrep
:pcre
答案 1 :(得分:17)
好的,轮到我了,我试一试:
find -type f -print0 | xargs -0 -L1 bash -c 'test "$(tail -c 1 "$0")" && echo "No new line at end of $0"'
答案 2 :(得分:8)
尝试一下:
find -type f -exec sh -c '[ -z "$(sed -n "\$p" "$1")" ]' _ {} \; -print
它将打印以空行结尾的文件的文件名。要打印不以空行结尾的文件,请将-z
更改为-n
。
答案 3 :(得分:3)
答案 4 :(得分:3)
答案 5 :(得分:2)
这是kludgy;肯定会有人做得更好:
for f in `find . -name '*.txt' -type f`; do
if test `tail -c 1 "$f" | od -c | head -n 1 | tail -c 3` != \\n; then
echo $f;
fi
done
N.B。这回答了标题中的问题,这与正文中的问题不同(正在查找以\ n \ n结尾的文件)。
答案 6 :(得分:2)
这应该可以解决问题:
#!/bin/bash
for file in `find $1 -type f -name "*.txt"`;
do
nlines=`tail -n 1 $file | grep '^$' | wc -l`
if [ $nlines -eq 1 ]
then echo $file
fi
done;
这样称呼:./script dir
E.g。 ./script /home/user/Documents/
- >列出/home/user/Documents
中以\n
结尾的所有文本文件。
答案 7 :(得分:2)
此页面上的大多数解决方案对我不起作用(FreeBSD 10.3 amd64)。伊恩威尔 OSX解决方案几乎总是有效,但很难遵循: - (
有一个简单的解决方案,几乎总是有效:(如果$ f是文件):
sed -i'' -e' $ a \' " $ F"
sed解决方案存在一个主要问题:它永远不会给你 只需检查(而不是附加换行符)的机会。
上述两种解决方案都无法用于DOS文件。我认为最多 便携/可编写脚本的解决方案可能是最简单的解决方案 我自己开发的: - )
这是基本的sh脚本,它结合了file / unix2dos / tail。在 生产,你可能需要使用" $ f"在引号和获取尾输出 (嵌入到名为last的shell变量中)为\" $ f \"
if file $f | grep 'ASCII text' > /dev/null; then
if file $f | grep 'CRLF' > /dev/null; then
type unix2dos > /dev/null || exit 1
dos2unix $f
last="`tail -c1 $f`"
[ -n "$last" ] && echo >> $f
unix2dos $f
else
last="`tail -c1 $f`"
[ -n "$last" ] && echo >> $f
fi
fi
希望这有助于某人。
答案 8 :(得分:1)
另一种选择:
$ find . -name "*.txt" -print0 | xargs -0I {} bash -c '[ -z "$(tail -n 1 {})" ] && echo {}'
答案 9 :(得分:1)
由于你的问题有perl标签,我会发一个使用它的答案:
find . -type f -name '*.txt' -exec perl check.pl {} +
其中check.pl如下:
#!/bin/perl
use strict;
use warnings;
foreach (@ARGV) {
open(FILE, $_);
seek(FILE, -2, 2);
my $c;
read(FILE,$c,1);
if ( $c ne "\n" ) {
print "$_\n";
}
close(FILE);
}
这个perl脚本只是打开,每次一个,作为参数传递的文件,只读取倒数第二个字符;如果它不是换行符,它只打印出文件名,否则它什么都不做。
答案 10 :(得分:1)
这个例子
单线:
find . -type f -exec sh -c 'file -b "{}" | grep -q text' \; -exec sh -c '[ "$(tail -c 1 "{}" | od -An -a | tr -d "[:space:]")" != "nl" ]' \; -print
更具可读性的版本
#!/bin/sh
find . \
-type f \
-exec sh -c 'file -b "{}" | grep -q text' \; \
-exec sh -c '[ "$(tail -c 1 "{}" | od -An -a | tr -d "[:space:]")" != "nl" ]' \; \
-print
最后,一个带有 -f 标志的版本来修复有问题的文件(需要 bash)。
#!/bin/bash
# Finds files without final newlines
# Pass "-f" to also fix those files
fix_flag="$([ "$1" == "-f" ] && echo -true || echo -false)"
find . \
-type f \
-exec sh -c 'file -b "{}" | grep -q text' \; \
-exec sh -c '[ "$(tail -c 1 "{}" | od -An -a | tr -d "[:space:]")" != "nl" ]' \; \
-print \
$fix_flag \
-exec sh -c 'echo >> "{}"' \;
答案 11 :(得分:0)
我能想到的最好的单线是:
git grep --cached -Il '' | xargs -L1 bash -c 'if test "$(tail -c 1 "$0")"; then echo "No new line at end of $0"; exit 1; fi'
这使用git grep
,因为在我的用例中,我想确保提交到git分支的文件以换行符结尾。
如果这在git repo之外是必需的,那么您当然可以只使用grep
。
grep -RIl '' . | xargs -L1 bash -c 'if test "$(tail -c 1 "$0")"; then echo "No new line at end of $0"; exit 1; fi'
为什么我要使用grep?因为您可以使用-I
轻松过滤出二进制文件。
然后在其他答案中找到通常的xargs / tailthing,如果文件没有换行符,则添加以1退出。因此,可以将其用于预提交的githook或CI。
答案 12 :(得分:0)
这是另一个使用小 bash 内置命令的示例,其中:
| grep '\.md$'
只过滤 md
文件)grep
命令用于扩展过滤器(如排除 | grep -v '\.git'
以排除 .git
下的文件代码基本上迭代 (for
) 所有文件(匹配您选择的条件 grep
),如果文件的最后 1 个字符 (-n "$(tail -c -1 "$file")"
) 不是空白行,它将打印文件名(echo "$file"
)。
详细代码:
for file in $(find . | grep '\.md$')
do
if [ -n "$(tail -c -1 "$file")" ]
then
echo "$file"
fi
done
更紧凑一点:
for file in $(find . | grep '\.md$')
do
[ -n "$(tail -c -1 "$file")" ] && echo "$file"
done
当然还有它的 1-liner:
for file in $(find . | grep '\.md$'); do [ -n "$(tail -c -1 "$file")" ] && echo "$file"; done