我正在尝试创建一个脚本,该脚本将删除OS X中的应用程序列表。 我的一般想法:
所以核心逻辑将是
我一直在使用find -exec,但是对其他方法持开放态度。
这是我找到的-exec不能正常工作的
find /Applications -maxdepth 3 -type f -name Info.plist -exec sh -c "grep '<string>Example</string>' | xargs dirname | xargs echo rm --" 2>/dev/null
我意识到
默认读取$ dir / Contents / Info CFBundleExecutable
可能比grep更好地提取软件包名称,但是不要认为这就是为什么以上都不起作用的原因(测试“ echo rm”根本没有输出,并插入tee命令以输出到文件也没有执行任何操作)。
上面的行(如果可行)将循环运行,以删除每个应用程序,并在变量中列出应用程序名称。
我完全欢迎其他方法,特别是如果有更有效的方法可以做到这一点。
答案 0 :(得分:1)
将逻辑保留在父外壳中而不是将其改组到子进程是比较明智的选择:
#!/usr/bin/env bash
# works correctly with names echo doesn't handle -- ones containing spaces, backslashes, etc
log_command() { printf '%q ' "$@" && echo; }
while IFS= read -r -d '' plist; do
if grep -e '<string>Example</string>' "$plist"; then
log_command rm -r -- "${plist%/*}"
fi
done < <(find /Applications -maxdepth 3 -type f -name Info.plist -print0)
请注意,<(...)
-process substitution是仅bash功能,因此,如果脚本以sh
而不是{{1 }}。
这也可以很容易地修改以使用更好的做法,因此很容易修改为:
bash
但是,如果您真的希望#!/usr/bin/env bash
log_command() { printf '%q ' "$@" && echo; }
while IFS= read -r -d '' plist; do
dir=${plist%/*}
if [[ "$(defaults read "$dir"/Contents/Info CFBundleExecutable)" = example ]]; then
log_command rm -r -- "$dir"
fi
done < <(find /Applications -maxdepth 3 -type f -name Info.plist -print0)
成为父进程,则可以执行以下操作:
find
使用find /Applications -maxdepth 3 -type f -name Info.plist -exec bash -c '
log_command() { printf '%s\n' "$@" && echo; }
for plist do
if grep -e "<string>Example</string>" "$plist"; then
log_command rm -r -- "${plist%/*}"
fi
done
' _ {} +
会将尽可能多的结果传递给-exec ... {} +
的每个副本。 bash
填充了_
,因此在命令行中找到并放置的文件名被放置在$0
,$1
等中;这就是$2
在没有给出明确列表的情况下循环显示的内容。
答案 1 :(得分:0)
由于将深度限制为3,实际上也是最小深度,因此和路径的其余部分将受到严格限制(必须为{{1} }),您实际上并不需要beta.39
。一个简单的glob模式就足够了,而且也应该更有效(因为它不必搜索*.app/Contents/
):
find