Bash 通过Shell脚本删除OS X应用程序
我正在尝试创建一个脚本,该脚本将删除OSX中的应用程序列表。 我的总体想法是: 应用程序只是OSX中的目录 这些目录有一个Contents子目录,其中包含一个Info.plist,可用于标识应用程序。 因此,核心逻辑是 沿着车道走 如果当前文件夹具有名为Contents的子文件夹,其中包含名为Info.plist的文件,该文件包含某些文本,请删除当前文件夹。 我一直在玩弄find-exec,但我对其他方法持开放态度 这就是我为find-exec所做的工作,它不太正常Bash 通过Shell脚本删除OS X应用程序,bash,macos,shell,Bash,Macos,Shell,我正在尝试创建一个脚本,该脚本将删除OSX中的应用程序列表。 我的总体想法是: 应用程序只是OSX中的目录 这些目录有一个Contents子目录,其中包含一个Info.plist,可用于标识应用程序。 因此,核心逻辑是 沿着车道走 如果当前文件夹具有名为Contents的子文件夹,其中包含名为Info.plist的文件,该文件包含某些文本,请删除当前文件夹。 我一直在玩弄find-exec,但我对其他方法持开放态度 这就是我为find-exec所做的工作,它不太正常 find /Applicat
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更好,但不要认为这就是为什么上面的方法无法从testecho rm获得任何输出,并且插入tee命令以输出到文件也没有任何作用
上面这一行,如果有效的话,将在一个循环中运行,每个应用程序都将被删除,并在一个变量中列出应用程序名称
我完全接受其他方法,尤其是如果有更有效的方法来实现这一点。将逻辑保留在父shell中,而不是将其转移到子流程中,这更明智:
#!/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)
但是,如果确实希望“查找”成为父进程,可以这样做:
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的每个副本。_u填充$0,因此在命令行中找到并放置的文件名将被放置在$1、$2中,以此类推;这就是在没有给出明确列表时循环的情况。因为您将其限制为3的深度,这实际上也是最小深度,路径的其余部分将受到高度约束,必须是*.app/Contents/您不需要查找。简单的glob模式应该足够了,而且应该更有效,因为它不必搜索内容/资源:
您希望代码如何将找到的名称传递给sh的副本?要明确的是,现在根本没有这样做。限制深度只是为了在应用程序文件夹中进行测试。对于部署,我将花费或取消限制。@RayMarquardt啊,那没关系。如果您有bashv4,那么可以使用globstar这样做,但是我认为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
' _ {} +
for plist in /Applications/*.app/Contents/Info.plist; do
if [ "$(defaults read "${plist%.plist}" CFBundleExecutable)" = Example ]; then
echo rm -R -- "${plist%/Contents/Info.plist}" # remove "echo" to actually do it
fi
done