逻辑运算符可以与 find 和 xargs 一起使用吗?
Can logical operators be used with find and xargs?
我有一个包含大约 5000 个文件的目录,其中一些文件是因语法错误而被错误写入的。我正在使用以下代码来识别哪些文件有错误:
ls -1 | while read a; do grep -q '^- ' $a || echo $a; done
我最初尝试使用 find
和 xargs
的组合,但我不知道如何添加我需要的布尔逻辑。
我的用例未 I/O 绑定并且完成速度足够快。但我很好奇是否可以在不依赖 bash 循环的情况下完成同样的操作。尽管对 Bash 很满意,但我倾向于严重依赖管道进入循环,这通常会导致 .
您可以在 find
:
中使用布尔逻辑
find -maxdepth 1 -type f \( -exec grep -q '^- ' {} \; -o -print \)
-o
选项是逻辑或。如果 -exec
执行的命令将 return 一个 non-zero return 值 -print
将打印文件名。
这是另一种方法,使用 grep -L
:
find -maxdepth 1 -type f -exec grep -L '^- ' {} \;
上面的代码将列出目录中的所有文件,这些文件的内容中不包含以破折号 + space -
开头的行。
要使上面的代码递归(即,将搜索扩展到所有子目录),只需删除 -maxdepth 1
部分。
来自 man grep
关于选项 -L
:
-L, --files-without-match Suppress normal output; instead print the name of each input file from which no output would normally have been
printed. The scanning will stop on the first match.
单独使用 grep
就足够了:
grep -d skip -L '^- ' *
注意:与 find
不同,这不会自动包含 隐藏 文件。
要递归搜索 ,请改用 grep -L '^- ' -R .
(尽管 -R
不是 POSIX-compliant,它适用于 GNU 和 BSD/macOS grep
).
-L
,如 中所述,打印每个输入文件的 路径 (按指定)not 包含搜索词。
-d skip
跳过目录(虽然选项 -d
不是 POSIX-compliant,GNU 和 BSD/macOS grep
都支持它)。
警告: 正如 hek2mgl 在评论中指出的那样, *
[=] 的文件名扩展后产生的命令行61=]可能太长,导致出现/usr/bin/grep: Argument list too long
.
等错误
(相比之下,如果使用 -R .
进行 grep
递归搜索,则不会遇到此问题。)
最大值。长度是platform-specific,可以用getconf ARG_MAX
查询,不过注意实际限制是低于,具体取决于您环境的大小 - 请参见this article。
实际上,5000 个文件可能不会有问题,即使在最大数量相对较低的平台上也是如此。长度,例如 macOS - 除非你有特别长的文件名 and/or 你的 globbing 模式有一个很长的路径组件 [1]
.
最近的 Linux 版本有更高的限制。
如果您确实达到了限制并且必须解决它,使用xargs
如下:
printf '%s[=11=]' * | xargs -0 grep -d skip -L '^- '
请注意,虽然 -0
读取 NUL-terminated 输入不是 POSIX-compliant,但 GNU 和 BSD/macOS xargs
.[=39 都支持它=]
如果输入文件名确实不适合 单个 命令行,xargs
将以最少 [=12] 的方式对输入进行分区=] 处理所有这些调用所必需的调用。
[1] macOS 10.12 有 262,144
字节 (256 KB) 的限制;如果我们保守地假设,在扣除环境的大小和命令行的固定部分后,我们的文件名列表得到 250,000
字节,这给我们每个文件名 250000 / 5000 == 50
字节 + space(列表分隔符),这样每个文件名最多可以有 49
个字节。
相比之下,Ubuntu 16.04 的限制高出 8 倍:2,097,152
字节 (2 MB)。
我有一个包含大约 5000 个文件的目录,其中一些文件是因语法错误而被错误写入的。我正在使用以下代码来识别哪些文件有错误:
ls -1 | while read a; do grep -q '^- ' $a || echo $a; done
我最初尝试使用 find
和 xargs
的组合,但我不知道如何添加我需要的布尔逻辑。
我的用例未 I/O 绑定并且完成速度足够快。但我很好奇是否可以在不依赖 bash 循环的情况下完成同样的操作。尽管对 Bash 很满意,但我倾向于严重依赖管道进入循环,这通常会导致
您可以在 find
:
find -maxdepth 1 -type f \( -exec grep -q '^- ' {} \; -o -print \)
-o
选项是逻辑或。如果 -exec
执行的命令将 return 一个 non-zero return 值 -print
将打印文件名。
这是另一种方法,使用 grep -L
:
find -maxdepth 1 -type f -exec grep -L '^- ' {} \;
上面的代码将列出目录中的所有文件,这些文件的内容中不包含以破折号 + space -
开头的行。
要使上面的代码递归(即,将搜索扩展到所有子目录),只需删除 -maxdepth 1
部分。
来自 man grep
关于选项 -L
:
-L, --files-without-match Suppress normal output; instead print the name of each input file from which no output would normally have been printed. The scanning will stop on the first match.
单独使用 grep
就足够了:
grep -d skip -L '^- ' *
注意:与 find
不同,这不会自动包含 隐藏 文件。
要递归搜索 ,请改用 grep -L '^- ' -R .
(尽管 -R
不是 POSIX-compliant,它适用于 GNU 和 BSD/macOS grep
).
-L
,如
-d skip
跳过目录(虽然选项 -d
不是 POSIX-compliant,GNU 和 BSD/macOS grep
都支持它)。
警告: 正如 hek2mgl 在评论中指出的那样, *
[=] 的文件名扩展后产生的命令行61=]可能太长,导致出现/usr/bin/grep: Argument list too long
.
等错误
(相比之下,如果使用 -R .
进行 grep
递归搜索,则不会遇到此问题。)
最大值。长度是platform-specific,可以用getconf ARG_MAX
查询,不过注意实际限制是低于,具体取决于您环境的大小 - 请参见this article。
实际上,5000 个文件可能不会有问题,即使在最大数量相对较低的平台上也是如此。长度,例如 macOS - 除非你有特别长的文件名 and/or 你的 globbing 模式有一个很长的路径组件 [1]
.
最近的 Linux 版本有更高的限制。
如果您确实达到了限制并且必须解决它,使用xargs
如下:
printf '%s[=11=]' * | xargs -0 grep -d skip -L '^- '
请注意,虽然 -0
读取 NUL-terminated 输入不是 POSIX-compliant,但 GNU 和 BSD/macOS xargs
.[=39 都支持它=]
如果输入文件名确实不适合 单个 命令行,xargs
将以最少 [=12] 的方式对输入进行分区=] 处理所有这些调用所必需的调用。
[1] macOS 10.12 有 262,144
字节 (256 KB) 的限制;如果我们保守地假设,在扣除环境的大小和命令行的固定部分后,我们的文件名列表得到 250,000
字节,这给我们每个文件名 250000 / 5000 == 50
字节 + space(列表分隔符),这样每个文件名最多可以有 49
个字节。
相比之下,Ubuntu 16.04 的限制高出 8 倍:2,097,152
字节 (2 MB)。