Разумнее хранить логику в родительской оболочке, а не перетасовывать ее в подпроцесс:
#!/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
зацикливается, если нет явного списка.