Кейс (Shell): найдите проблему в простом bash-скрипте, который ломается на именах файлов с пробелами: for f in $(ls *.txt); do mv "$f" "${f%.txt}.bak"; done — объясните причину и предложите корректный вариант
Проблема: конструкция `for f in $(ls *.txt); …` ломается, потому что `$(...)` выполняет командную подстановку, затем оболочка выполняет разбиение по пробелам/символам из `IFS` и словоразделение — имена файлов с пробелами (или табами, переводами строк) разбиваются на несколько слов. Кроме того, парсить вывод `ls` ненадёжно (имена могут содержать новые строки и другие спецсимволы). Коррекция (простой и обычно достаточный вариант): for f in *.txt; do [ -e "$f" ] || continue mv -- "$f" "${f%.txt}.bak" done Пояснения: - `for f in *.txt` использует расширение шаблона оболочкой и даёт каждый файл как отдельный элемент (пробелы внутри имён сохраняются). - `"$f"` — обязательное кавычение при работе с именами. - `--` в `mv --` защищает от имён, начинающихся с `-`. - `[ -e "$f" ] || continue` пропускает случай, когда шаблон не совпал и остался литералом `*.txt`. Ещё более надёжный вариант (обрабатывает любые символы, включая переводы строк): find . -maxdepth 1 -type f -name '*.txt' -print0 | while IFS= read -r -d '' f; do mv -- "$f" "${f%.txt}.bak" done (в этом варианте имена будут с префиксом `./`; при необходимости их можно убрать).
Коррекция (простой и обычно достаточный вариант):
for f in *.txt; do
[ -e "$f" ] || continue
mv -- "$f" "${f%.txt}.bak"
done
Пояснения:
- `for f in *.txt` использует расширение шаблона оболочкой и даёт каждый файл как отдельный элемент (пробелы внутри имён сохраняются).
- `"$f"` — обязательное кавычение при работе с именами.
- `--` в `mv --` защищает от имён, начинающихся с `-`.
- `[ -e "$f" ] || continue` пропускает случай, когда шаблон не совпал и остался литералом `*.txt`.
Ещё более надёжный вариант (обрабатывает любые символы, включая переводы строк):
find . -maxdepth 1 -type f -name '*.txt' -print0 | while IFS= read -r -d '' f; do
mv -- "$f" "${f%.txt}.bak"
done
(в этом варианте имена будут с префиксом `./`; при необходимости их можно убрать).