Проблемы с цитатой в Bash-скрипте
У меня есть следующий скрипт Bash:
DIR="~/Folder/With\ Spaces"
CMD="find $DIR -type f"
# echo showing hidden characters
echo $CMD | cat -v
while read line
do
echo $line
done < <($CMD)
Выход:
find ~/Folder/With\ Spaces -type f
find: ~/Folder/With\: No such file or directory
find: Spaces: No such file or directory
Я прошел через все возможные способы: одинарные и двойные кавычки, обратный слеш и отсутствие обратного слеша, кавычки вокруг переменной в других строках, без кубиков.
Если я правильно понимаю, CMD должно быть следующим:
find ~/Folder/With\ Spaces -type f
Это должно работать нормально, и так как find
не может использовать кавычки вокруг своего пути, это правильный способ сделать это. Эхо показывает, что это соответствует. Ввод этой строки в командной строке работает нормально. Опять же, echo
Команда печатает это. Но вывод сценария говорит, что происходит что-то еще, вероятно, на done
строка, где выполняется команда.
Как мне заставить Bash интерпретировать имя файла как один путь в этом контексте? И почему? Обратная косая черта (чтобы она не интерпретировалась как две части, разделенные пробелами) рассматривается как часть строки, так где же она разделяется и почему?
1 ответ
Bash никогда не оценивает данные как код, но он делает некоторые вещи, которые могут заставить вас думать, что это происходит (а именно расщепление слов и глобализация). поскольку \
является частью синтаксиса оболочки, он не интерпретируется как escape-последовательность при раскрытии переменной.
Вот как вы должны это сделать:
DIR=~/"Folder/With Spaces" # ~ doesn't expand in quotes, and there's no "\".
CMD=(find "$DIR" -type f) # use an array to keep track of words
# Print the words escaped so you know what will actually be executed
printf "%q " "${CMD[@]}" | cat -v
echo
while IFS= read -r line # don't split or interpret words
do
echo "$line" # use quotes to prevent globbing and word splitting
done < <("${CMD[@]}") # run the command in the array without spacing issues