Ответ @Olorins является правильным ответом на этот вопрос, но я хочу добавить дополнительную информацию , почему это не работает:
Вы можете использовать любой из этих:
rm "dir with spaces"
rm dir\ with\ spaces
dir="dir with spaces"; rm "$dir"
Но это не сработает:
dir="dir\ with\ spaces";
rm "$dir" # the backslash will be taken literally inside quotes
rm $dir # this should work, shouldn't it? Please read below.
Последний вариант поначалу казался мне неинтуитивным. Но bash расширяет содержимое переменных, добавляя кавычки перед выполнением .
Вы можете использовать set -x
, чтобы увидеть, что на самом деле выполняется:
( var="a\ b"; set -x; echo $var; )
+ echo 'a\' b
a\ b
Хотя вывод выглядит хорошо, пробел по-прежнему не экранирован, поскольку \
заключен в одинарные кавычки.
У вас есть:
printf "%s\n" $FIND_RESULTS | sort |
while read -r line; do
...
done
echo "${!my_gems[@]}"
, где, независимо от отступа, echo
находится вне конвейера. Bash по умолчанию запускает все части конвейера в подоболочках, поэтому назначения в цикле while
не видны после завершения конвейера. Shellcheck.net также предупреждает об этом :
Line 32:
my_gems[$KEY]=$values
^-- SC2030: Modification of my_gems is local (to subshell caused by pipeline).
К сожалению, это не дает обходных путей.
В Bash вы можете либо включить опцию lastpipe
, либо заменить канал подстановкой процесса:
shopt -s lastpipe
echo test | while read line; do
out=$line
done
echo "out=$out"
или
while read line; do
out=$line
done < <(echo test)
echo "out=$out"
(lastpipe
, вероятно, не сработает, если вы попробуете его в интерактивной оболочке, так как он привязан к управлению заданиями , а не .)
См.:Почему моя переменная локальна в одном цикле while read, но не в другом похожем цикле?
В любом случае это выглядит немного странно:
FIND_RESULTS=$(find...)
printf "%s\n" $FIND_RESULTS
find
выводит имена файлов, разделенные символами новой строки, что нормально, если вы знаете, что имена файлов не содержат их. Но здесь круговой обход -переменной и разделение слова из расширения без кавычек также разделяет любые имена файлов пробелами.
Вы можете просто запустить find... | while...
напрямую. Или while...; done < <(find...)
.
Кроме того, обратите внимание, что вы почти всегда должны использовать while IFS= read -r line; do
, чтобы предотвратить read
от нарушения начальных и конечных пробелов. Ну, я надеюсь, что ваши имена файлов тоже не содержат их, но в любом случае.
Сейчас я не могу найти хороший справочный вопрос, но он касается IFS
пробелов. Другие начальные и конечные разделители не удаляются с помощью read
только для одного поля. Например. IFS=": " read -r foo <<< "::foobar "
оставляет foo
с буквальным ::foobar
. Двоеточие сохранено, но конечные пробелы удалены.