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}"

У меня есть два вопроса:

  1. Я хотел бы знать, почему последний и только последний работал. Это связано с IFS бит установлен раньше?

  2. Если есть более простой способ сделать это, что бы это было? Опять же надо все схватить .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 Если переменная содержит символы подстановки, у вас будут проблемы, потому что символы подстановки раскрываются после раскрытия переменных без кавычек. Оставляйте переменные без кавычек только в том случае, если вам действительно нужно разбивать слова на части.

Другие вопросы по тегам