逻辑运算符能否与find和xargs一起使用?

4

我有一个包含大约5000个文件的目录,其中一些文件由于语法错误而被误写。我正在使用以下代码来识别哪些文件存在错误:

ls -1 | while read a; do grep -q '^- ' $a || echo $a; done

我最初尝试使用findxargs的组合,但我无法弄清楚如何添加所需的布尔逻辑。

我的用例不受I/O限制,完成得足够快。但我很好奇是否可以在不依赖于bash循环的情况下完成相同的操作。虽然我熟悉Bash,但我倾向于过度依赖管道进入循环,这经常导致令人发指的缓慢性能


1
你最终想要实现什么?显示包含字符串的文件名吗? - Inian
显示不匹配此正则表达式的文件。布尔逻辑或是关键点。 - Zhro
3个回答

3

您可以使用布尔逻辑与find

find -maxdepth 1 -type f \( -exec grep -q '^- ' {} \; -o -print \)

-o选项是逻辑或。如果由-exec执行的命令返回非零返回值,则-print将打印文件名。


1
是的,不过-type f应该无论如何都会排除当前文件夹(.) - hek2mgl
因为“.”是表示文件夹的符号,所以“-type f”命令会失败。这将导致执行“-print”命令。你可以将该行代码(去掉括号)理解为“-maxdepth 1 && -type f && -exec ... || -print”。 - hek2mgl
那很有道理。谢谢你的澄清。 - Zhro
不客气!这是find命令中一个有点不常用但非常强大的功能。 - hek2mgl
什么?他们(版主)真的在这里删除了两条评论。讨论现在被打断了!天啊,太疯狂了!我真的很想知道为什么!那里面没有任何不好的东西,意思是0。@Zhro和我只是讨论答案,而答案本身就有问题...我猜可能是因为它太详细了。我还是无法相信! - hek2mgl
显示剩余4条评论

2

这里有另一种使用 grep -L 的方法:

find -maxdepth 1 -type f -exec grep -L '^- ' {} \;

上述代码将列出目录中所有不包含以破折号 + 空格 - 开头的行的文件。
要使上述代码递归(即扩展搜索到所有子目录),只需删除 -maxdepth 1 部分。
关于选项 -L,来自 man grep
-L, --files-without-match 阻止正常输出;而是打印每个输入文件的名称,从其中未打印任何输出。扫描将在第一个匹配项处停止。

2

单独使用grep足以完成任务:

grep -d skip -L '^- ' *

注意:与find不同的是,这不会自动包含隐藏文件。
要进行递归搜索,请改用grep -L '^- ' -R .(尽管-R不符合POSIX标准,但它适用于GNU和BSD/macOS grep)。

-L,如Jamil Said的有用答案所述,打印每个输入文件(指定的)路径,该路径未包含搜索项。

-d skip跳过目录(虽然-d选项不符合POSIX标准,但它受到GNU和BSD/macOS grep的支持)。


注意:正如hek2mgl在评论中指出的那样,*的文件名扩展结果可能会太长,导致出现错误,例如/usr/bin/grep: Argument list too long
(相比之下,如果使用-R .使grep进行递归搜索,则不会遇到此问题。)

最大长度是平台特定的,可以使用getconf ARG_MAX查询,但请注意,实际限制取决于您的环境的大小,比这低 - 请参见此文章

实际上,在5000个文件左右通常不会有问题,即使在具有相对较低的最大长度的平台(如macOS)上 - 除非您的文件名异常长和/或您的通配模式具有漫长的路径组件[1]
最近的Linux版本具有更高的限制。

如果遇到限制并且必须解决它,请使用xargs,如下所示:

printf '%s\0' * | xargs -0 grep -d skip -L '^- '

请注意,使用-0读取以NUL结尾的输入虽然不符合POSIX标准,但是GNU和BSD/macOS的xargs都支持它。
如果输入的文件名确实不能适应单个命令行,xargs将对输入进行分区,以便产生最少的grep调用来处理所有文件名。
[1] macOS 10.12的限制为262,144字节(256 KB);如果我们保守地假设,在扣除环境的大小和命令行的固定部分后,我们得到250,000字节的文件名列表,这给了我们每个文件名+空格(列表分隔符)允许长达49字节。相比之下,Ubuntu 16.04的限制高出8倍:2,097,152字节(2 MB)。

问题出在通配符上。正如楼主所说,那个文件夹里有5000个文件。这会导致“参数列表过长”的错误。你需要使用“-r”(或“-R”)选项。 - hek2mgl
@mklement0 很好的回答。+2(不幸的是不允许)我很惊讶5000不是问题。我知道限制是可配置的,但我低估了它的(默认)值。 - hek2mgl
1
@hek2mgl:谢谢。我已经添加了一个计算作为脚注。根据http://www.in-ulm.de/~mascheck/various/argmax/,在现代平台(如Linux和macOS)上,您需要重新编译内核才能增加`ARG_MAX`限制。 - mklement0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接