В этом скрипте есть много мест, где у вас есть ссылки на переменные без двойных кавычек.Это означает, что значения переменных будут подвержены разбивке слов и расширению подстановочного знака, что может иметь различные странные эффекты.
Конкретная проблема, с которой вы сталкиваетесь, связана с ссылкой на переменную без кавычек в четвертой от последнейлиния, ${cmd[@]}
.При cmd=( echo "hello world" )
разбиение слов делает это эквивалентным echo hello world
, а не echo "hello world"
.
Исправление одной строки решит вашу текущую проблему, но есть ряд других ссылок на переменные без кавычек, которые могут вызвать другиепроблемы позже.Я рекомендую исправить всех из них.Рекомендация Сайруса о shellcheck.net хороша для их указания, а также отметит некоторые другие вопросы, которые я не буду здесь освещать.Одна вещь, о которой не следует упоминать, это то, что вам следует избегать имен переменных all-caps (DIR
, TUSAGE
и т. Д.) - есть куча переменных all-caps со специальным значением, и их легко случайно использовать повторноиз них и заводить со странными эффектами.Переменные в нижнем и нижнем регистре безопаснее.
Я также рекомендую не использовать \t
и \n
в строках и рассчитывать на echo
для перевода их во вкладки и переводы строки соответственно.Некоторые версии echo
делают это автоматически, некоторые требуют опции -e
, чтобы сказать им сделать это, некоторые выводят «-e» как часть их вывода ... это беспорядок.В bash вы можете использовать $'...'
для прямого перевода этих escape-последовательностей, например:
tusage="$tusage"$' \t--help (shows this help output)\n' # Note mixed quoting modes
echo "$tusage" # Note that double-quoting is *required* for this to work right
Вы также должны исправить листинг файла, чтобы он не зависел от того, чтобы быть без кавычек (см. Комментарий Чепнера).Если вам не нужно сканировать подкаталоги $ DIR / scripts, вы можете сделать это с помощью простого подстановочного знака (обратите внимание на строчные буквы и переменную в двойных кавычках, но подстановочный знак нет):
arr=( "$dir/scripts"/*.sh )
Если вам нужно посмотреть в подкаталогах, это сложнее.Если у вас bash v4, вы можете использовать подстановочный знак globstar, например:
shopt -s globstar
arr=( "$dir/scripts"/**/*.sh )
Если ваш скрипт может работать под bash v3, см. BashFAQ # 20: «Как найти и безопаснообрабатывать имена файлов, содержащие символы новой строки, пробелы или оба? ", или просто используйте это:
while IFS= read -r -d '' f <&3; do
if [ -f $f ]
# ... etc
done 3< <(find "$dir/scripts" -type f -name '*.sh' -print0)
(Это моя любимая идиома" просто работает "для перебора совпадений find
. Хотядля этого требуется bash, а не какая-то общая оболочка POSIX.)