Bash: путаница в расширении var, возможно, из-за IFS
После прочтения о получении файлов с пробелами в имени с помощью find
Я собрал небольшой кусок кода, чтобы захватить все .sh
файлы в каталоге и сделать их исполняемыми:
find . -type f -name '*.sh' -print0 |
while IFS= read -r -d '' file; do
name=$(printf '%s\n' "$file" | sed "s|^\./||")
echo $name
if ! [[ -x $name ]] ; then
chmod +x "${name}"
fi
done
Третья до последней строчки доставила мне больше всего хлопот. Я прошел все 3 перестановки:
chmod +x $name
chmod +x ${name}
chmod +x "${name}"
У меня есть два вопроса:
Я хотел бы знать, почему последний и только последний работал. Это связано с
IFS
бит установлен раньше?Если есть более простой способ сделать это, что бы это было? Опять же надо все схватить
.sh
файлы в текущем каталоге - все из которых имеют пробелы в именах файлов - и делают их исполняемыми.
1 ответ
Когда вы помещаете переменную в начало команды, она применяется только к этой команде. Итак IFS
Вы установили ранее, был использован только read
команда. Остальная часть кода использует значение по умолчанию IFS
, который имеет пробел в качестве разделителя полей.
Если вы хотите IFS
Для применения ко всему коду, вы должны сделать это как отдельный оператор, а не как префикс команды.
IFS=
find . -type f -name '*.sh' -print0 |
while read -r -d '' file; do
name=$(printf '%s\n' "$file" | sed "s|^\./||")
echo $name
if ! [[ -x $name ]] ; then
chmod +x "${name}"
fi
done
Но в целом вы должны указать свои переменные. Даже если IFS
Если переменная содержит символы подстановки, у вас будут проблемы, потому что символы подстановки раскрываются после раскрытия переменных без кавычек. Оставляйте переменные без кавычек только в том случае, если вам действительно нужно разбивать слова на части.