这是我的用例:
搜索整个机器,找到任何名为 X 的目录
当然,这条线有效:
find / -type d -name "X"
但是,它有点慢,而且我认为它使用了大量资源。
为了提高速度,我考虑将查找结果传输到其他目录中,以过滤可能的搜索结果。例如,只查找根目录中首字母大写的目录,然后在其中查找名为X。
find / -maxdepth 1 -type d -name "/[A-Z]*" | xargs find -type d -name "X"
然而,这并没有奏效。
我已经看过了如何将 find 的输出通过管道传输到另一个 find 中但我找不到一些发现的管道说明。
如何将查找内容通过管道传输到另一个查找内容?
答案1
你能find
在 another 的结果上运行find
,但不使用该语法。
find / -maxdepth 1 -type d -name "/[A-Z]*" | xargs find -type d -name "X"
首先,您不能在任何命令或其他命令xargs
的输出上使用类似的方法,除非它输出的文件名都不包含任何空白字符、引号或反斜杠(或某些实现中的非字符)。find
find
如果您希望能够处理任意文件,则只能在输出(也是非标准)上使用xargs
非标准选项。其本身的输出根本无法进行后处理(请参阅-0
find -print0
-print0
find -print
为什么循环查找的输出是不好的做法?)。
另外,在这里,xargs
将附加第二个命令的文件路径find
,并将它们放在构成过滤条件的谓词之后。find
必须给出要操作的文件列表前任何谓词。
更一般地,很少需要xargs
在 的输出上使用,因为它有自己的内置(并且更可靠且通常更高效)支持在其使用/ (以及某些/ )谓词找到的文件上运行命令。find
find
-exec
-ok
-execdir
-okdir
但与 一样xargs
,您需要确保第二个文件列表find
位于谓词之前,因此它必须是:
find / -maxdepth 1 -name '[[:upper:]]*' -type d -exec sh -c '
exec find "$@" -name X -type d' sh {} +
我们使用like-exec cmd {} +
的形式传递尽可能多的可能路径,但也只能在最后传递它们。用于将那些移动到第二个正确的位置。-exec
xargs
cmd
sh
find
另请注意,-name
匹配的是文件名,而不是其完整路径(您需要-path
)。因此,我们[[:upper:]]*
不需要/[[:upper:]]*
(也不需要[A-Z]*
根据区域设置匹配的内容通常相当随机)匹配以大写字母开头的文件名。
使用 GNU 的下一个版本find
(或其当前的开发版本),您还可以执行以下操作:
find / -maxdepth 1 -name '[[:upper:]]*' -type d -print0 |
find -files0-from - -name X -type d
在这里,您可以通过一次调用来完成整个过程find
:
find / -path '/[![:upper:]]*' -prune -o -name X -type d -print
我们告诉在查找名为 X 的目录之前find
修剪以名称以大写字母以外的任何字符开头的目录开头的树分支。/
请注意,对于某些系统(包括GNU 系统上的 GNU)find
上的某些实现,可能无法匹配文件名中当前语言环境中无效文本的部分。find
*
例如,上面的命令会发现/stéphane/X
即使s
不是大写字母,如果它é
是用 iso8859-1 编码的,并且当前语言环境使用 UTF-8 作为其字符映射(其中 0xe9 字节无法解码为字符,因此*
无法不匹配),并且第一个命令将/Stéphane/X
因同样的原因而无法找到。
zsh
glob 不存在此类问题,因为将无法解码为字符的每个字节视为未定义的字符,因此您可以这样做:
print -rC1 /[[:upper:]]*/**/X(ND/)
或者,如果您不需要对列表进行o
排序,则可以进行轻微的优化:
print -rC1 /[[:upper:]]*/**/X(ND/oN)
请注意,它将包括/SymLink/.../X
目录。为了避免这种情况:
(){print -rC1 $^@/**/X(ND/oN)} /[[:upper:]]*(N/oN)
或者:
print -rC1 /[[:upper:]]*(N/oNe['reply=($REPLY/**/X(ND/oN)'])
这类似于两阶段find
方法:在一个 glob 中查找名称以大写字母开头的目录,然后将其中的所有 X 目录作为单独的 glob。
答案2
您的任务是找到/
首字母大写的子目录,然后提取这些子目录的路径名X
。
对于find
,我会这样做,假设没有数千个/
首字母大写的目录,
find /[[:upper:]]*/X -prune -type d -print
上面,我们find
使用一组顶级搜索路径进行调用。这些路径名恰好对应于我们实际要查找的目录名。唯一的任务find
是调查其中的每一个并打印目录。
您也可以find
完全跳过,而只是使用
printf '%s\n' /[[:upper:]]*/X/
这里唯一的区别是该模式可能与目录的符号链接匹配。如果这对您很重要,您可以对匹配名称进行更明确的测试,并告诉 shell(我假设是bash
)也匹配隐藏名称:
shopt -s nullglob
for name in /[[:upper:]]*/X/; do
[ -L "$name" ] && continue
printf '%s\n' "$name"
done
反复阅读您的问题几次后,我意识到我不知道您是否想要搜索X
递归的或不。在上面的讨论中,我假设你这样做不是想要递归搜索。
如果你做想要递归搜索,那么你会使用
find /[[:upper:]]* -name X -type d -print
没有什么可以使这个速度更快,除非您将搜索限制为更少的顶级搜索路径,或者修剪您所使用的已知路径。知道您不想搜索,例如避免输入任何tmp
目录,
find /[[:upper:]]* -name X -type d -print -o -name tmp -prune
您可能希望将搜索限制为单个文件系统:
find /[[:upper:]]* -xdev -name X -type d -print -o -name tmp -prune
在这里,来自顶级搜索路径的搜索永远不会跨越文件系统边界。