我有一个大约5000个文件的目录,其中一些错误地写入了语法错误。我使用以下代码来识别哪些文件有错误:
ls -1 | while read a; do grep -q '^- ' $a || echo $a; done
我最初尝试使用find
和xargs
的组合,但我无法弄清楚如何添加我需要的布尔逻辑。
我的用例不是I / O绑定并且足够快地完成。但我很好奇,看看是否可以在不依赖bash循环的情况下完成相同的操作。虽然对Bash感到满意,但我倾向于严重依赖管道进入循环,这通常导致mind numbingly slow performance。
答案 0 :(得分:3)
您可以将布尔逻辑与find
:
find -maxdepth 1 -type f \( -exec grep -q '^- ' {} \; -o -print \)
-o
选项是逻辑OR。如果-exec
执行的命令将返回非零返回值-print
将打印文件名。
答案 1 :(得分:2)
以下是使用grep -L
:
find -maxdepth 1 -type f -exec grep -L '^- ' {} \;
上面的代码会列出目录中所有文件,这些文件的内容中不包含以dash + space -
开头的行。
要使上面的代码递归(即,将搜索扩展到所有子目录),只需删除-maxdepth 1
部分。
从man grep
关于选项-L
:
-L, - files-without-match抑制正常输出;而是打印每个输入文件的名称,通常没有输出 打印。扫描将在第一场比赛中停止。
答案 2 :(得分:2)
单独使用grep
就足够了:
grep -d skip -L '^- ' *
注意:与find
不同,这不会自动包含隐藏文件。
要以递归方式搜索,请改用grep -L '^- ' -R .
(尽管-R
不符合POSIX标准,但它适用于GNU和BSD / macOS grep
)。
-L
,如Jamil Said's helpful answer中所述,打印不包含搜索词的每个输入文件的路径(如指定的那样) 。
-d skip
跳过目录(而选项-d
不符合POSIX标准,GNU和BSD / macOS grep
都支持它。
警告:正如hek2mgl在评论中指出的那样,在*
的文件名扩展之后产生的命令行可能太长,导致/usr/bin/grep: Argument list too long
等错误
(相反,如果您使用grep
递归搜索-R .
,则您不会遇到此问题。)
最大。长度是特定于平台的,可以使用 getconf ARG_MAX
查询,但请注意实际限制低于 ,具体取决于关于环境的大小 - 请参阅this article。
实际上,5000个文件可能不会出现问题,即使在最大值相对较低的平台上也是如此。长度,例如macOS - 除非你有特别长的文件名和/或你的globbing模式有一个冗长的路径组件 [1]
。
最近的Linux版本有更高的限制。
如果达到了限制并且必须解决此问题,使用xargs
,如下所示:
printf '%s\0' * | xargs -0 grep -d skip -L '^- '
请注意,虽然读取NUL终止输入的-0
不符合POSIX标准,但GNU和BSD / macOS xargs
都支持它。
如果输入文件名确实不适合单个命令行,xargs
将以导致最少grep
次调用的方式对输入进行分区必须处理所有这些。
[1] macOS 10.12的限制为262,144
字节(256 KB);如果我们保守地假设,在扣除环境的大小和命令行的固定部分之后,我们的文件名列表得到250,000
字节,这给了我们每个文件名250000 / 5000 == 50
个字节+空格(列表分隔符),以便允许每个文件名长达49
个字节
相比之下,Ubuntu 16.04的限制高出8倍:2,097,152
字节(2 MB)。