Удалить приложения OS X через Shell Script - PullRequest
0 голосов
/ 28 января 2019

Я пытаюсь создать скрипт, который удалит список приложений в OS X. Мое общее мнение:

  1. Приложения - это просто каталоги в OS X
  2. Эти каталогииметь подкаталог Contents, содержащий Info.plist, который можно использовать для идентификации приложения.

Таким образом, основная логика будет

  1. Walk the drive
  2. Если в текущей папке есть подпапка с именем 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, для извлечения имени пакета, но не думайте, что поэтому вышеприведенное не работает (без вывода из теста) echorm "и вставка командычтобы вывод в файл тоже ничего не делал).

Приведенная выше строка будет работать в цикле для каждого удаляемого приложения со списком имен приложений в переменной.

Я полностью открыт для других подходов, особенно если есть более эффективный способ сделать это.

Ответы [ 2 ]

0 голосов
/ 28 января 2019

Поскольку вы ограничиваете его глубиной до 3, а это также практически минимальная глубина, и остальная часть пути будет сильно ограничена (это должно быть *.app/Contents/), выдействительно не нужно find.Простого шаблона глобуса должно быть достаточно, и он также должен быть более эффективным (поскольку он не должен искать, например, Contents/Resources):

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
0 голосов
/ 28 января 2019

Разумнее хранить логику в родительской оболочке, а не перетасовывать ее в подпроцесс:

#!/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)

Обратите внимание, что <(...) - подстановка процесса - этофункция только для bash, поэтому она не гарантированно сработает, если ваш скрипт запускается с sh вместо 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 и т. Д .;это то, что for зацикливается, если нет явного списка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...