如何从 Bash find 命令的搜索路径中排除 Mac 包文件?
macOS 有一些实际上是 unix 目录的“文件”。 这些称为“包”。 Mac 应用程序文件就是一个很好的例子,但还有其他例子。 不幸的是,我没有看到任何查找开关来排除包。
这是一个不起作用的典型查找命令。 它将在 .app 文件内搜索:
find /Applications -type f -path ./*.app -prune -o -print
在这种情况下,我希望它列出实际的 .app 文件,但不在其中搜索。
我尝试过很多变体,但没有一个有效。
以下是一些其他典型的文件扩展名,它们实际上是包:
.app .pkg .scptd
插入一个正则表达式标准,该标准对包目录中的所有内容返回 false。 不幸的是,这确实意味着必须列出您希望排除其内容的包目录的文件扩展名。 我在我的正则表达式字符串中列出了其中的一些:
find -E /Applications ! -iregex '.*\.(app(download)?|scptd|pkg|bundle|qlgenerator|c?action|dictionary|cannedSearch|photoslibrary)/.+'
试试这个。我从另一个答案中得到了捆绑测试(来自用户anonymous-coward)。将其放入一个小脚本中并将其命名为“bundle”,如下所示:
#!/bin/bash
content_tree=$(mdls -name kMDItemContentTypeTree "$@" | grep -E '\"com.apple.bundle\"')
[[ ! -z "$content_tree" ]] && exit 0 || exit 1
(请随意改进我的 bash。)如果参数是捆绑包的路径,则捆绑包返回 0(成功),否则返回 1。它生成一些特定于 Mac 的元数据并查找捆绑包特征。如果您希望更具体地避免包而不是其他类型的捆绑包,您可以查找“com.apple.package”。您的
bundle
脚本可以选择您想要的任何内容。在某些文件上运行 mdls -name kMDItemContentTypeTree
并查看出现的内容,这将告诉您要传递给 grep
的正则表达式。您可以对文件扩展名等进行额外的测试。然后像这样形成你的 find
命令:
find /Applications \( -exec bundle {} \; -print -prune \) -or -print
我刚刚使用了
Applications
,因为它是一个示例,您可以在其中找到很多捆绑包和包。如果 shell 结果不为 0,则 -exec
标记将返回 false(因为作为 shell 结果,0 始终表示“成功”)。因此,-or
左侧的表达式意味着如果某个东西是一个包,我们将打印它的完整路径,而-prune
意味着我们不会继续进入该目录。 -print
右侧看似多余的-or
是因为如果您使用-exec
或其他一些运算符,find
会抑制所有默认打印,因此如果它是捆绑包(或包或脚本检测到的任何内容),如果不是,还打印路径。注意:关键是在测试结束时在 \;
和 +
之前使用 -print
而不是 -prune
。否则,find
会将大量文件分组并传递给 bundle
,并且您需要为每个文件获得一个答案。您可以将 -print
运算符替换为 -exec
任一侧或两侧的 -or
,以防您想以某种方式处理文件而不仅仅是查找文件。事实证明,这是您想要以不同方式处理的任意两类文件的示例。希望这有用。这是一个有趣的练习,实际上在思考形成 find
表达式方面非常有趣。
为了与 @cycollins 优秀的答案相吻合,这是辅助脚本的另一种形式(以及否定的风格),它更加简洁:
将其另存为
is_bundle
中的某个位置 $PATH
:
#!/usr/bin/env bash
mdls -name kMDItemContentTypeTree "$1" | egrep -q '\"com.apple.(bundle|package)\"'
并将其另存为
is_not_bundle
:
#!/usr/bin/env bash
mdls -name kMDItemContentTypeTree "$1" | egrep -q '\"com.apple.(bundle|package)\"'
[ $? -eq 0 ] && exit 1 || exit 0
以下是一些使用示例:
仅查找包含<pattern>
的
目录(完全忽略捆绑包)
find -s . -type d -iname "*pattern*" -exec is_not_bundle {} \; -print
找到任何包含
<pattern>
的东西——不要陷入捆绑:
find -s . -iname "*pattern*" \( -exec is_bundle {} \; -print -prune -or -print \)
查找目录或捆绑包(但不要深入其中)
find -s . -type d -mindepth 1 \( -exec is_bundle {} \; -print -prune -or -print \)
仅查找捆绑包
find -s . -type d -exec is_bundle {} \; -print -prune
查找匹配的捆绑包
<pattern>
find -s . -iname "*pattern*" -exec is_bundle {} \; -print -prune
这个答案特定于OP的主要问题,是一个按名称查找应用程序的简化查询,同时特别避免在应用程序包内搜索。
我遇到了同样的问题(找到一个应用程序,但在应用程序中找不到)。我要么没有得到结果、出现错误,要么搜索会挂起很长时间。
经过大量的尝试和错误,我将其缩减为以下命令,该命令将很快返回与查询的名称字符串匹配的应用程序的完整路径名和其他属性:
sudo find . -iname console.app ! -ipath *.app/contents* -ls
以下是其工作原理的详细说明:
# invoke su for elevated permissions to avoid a number of "Permission denied" errors
sudo
# find . = find in the current terminal path and subfolders
# find /Applications = explicitly search the root Applications folder
# (even if it isn't the current directory in terminal)
# hint: you can easily check the current path using the pwd command
find .
# do a case-insensitive name search (use -name for case-sensitive)
# for strings in the name of the app (partial filename), use wildcards
# for example: -iname *syst*pref* or -iname *sys*event*app
-iname console.app
# (case-insensitive) NOT/excluding anything in the 'contents' folder of an app
# (which I think every app should have as its first subfolder)
! -ipath *.app/contents*
# note: if there's a space in either the -iname or -ipath pattern/expression
# enclose the pattern in 'single' or "double" quotes
# lastly, this will list the path and other attributes/properties of the results found
-ls
希望这对找到此线程并特别想要搜索特定包的其他人有所帮助,同时避免在该类型的包中搜索。