Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 通过Shell脚本删除OS X应用程序_Bash_Macos_Shell - Fatal编程技术网

Bash 通过Shell脚本删除OS X应用程序

Bash 通过Shell脚本删除OS X应用程序,bash,macos,shell,Bash,Macos,Shell,我正在尝试创建一个脚本,该脚本将删除OSX中的应用程序列表。 我的总体想法是: 应用程序只是OSX中的目录 这些目录有一个Contents子目录,其中包含一个Info.plist,可用于标识应用程序。 因此,核心逻辑是 沿着车道走 如果当前文件夹具有名为Contents的子文件夹,其中包含名为Info.plist的文件,该文件包含某些文本,请删除当前文件夹。 我一直在玩弄find-exec,但我对其他方法持开放态度 这就是我为find-exec所做的工作,它不太正常 find /Applicat

我正在尝试创建一个脚本,该脚本将删除OSX中的应用程序列表。 我的总体想法是:

应用程序只是OSX中的目录 这些目录有一个Contents子目录,其中包含一个Info.plist,可用于标识应用程序。 因此,核心逻辑是

沿着车道走 如果当前文件夹具有名为Contents的子文件夹,其中包含名为Info.plist的文件,该文件包含某些文本,请删除当前文件夹。 我一直在玩弄find-exec,但我对其他方法持开放态度

这就是我为find-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更好,但不要认为这就是为什么上面的方法无法从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