почему ошибка цикла zsh » для «с командой» не найдена: filename.txt»? несмотря на filename.txt быть параметром, а не командой

#shell #zsh

Вопрос:

В следующей истории оболочки показаны две попытки переименования файлов, вторая попытка удалась. Но с первой попытки этого не произошло, и я понятия не имею, почему…

 ❯ ls
step-10.txt  step-12.txt  step-14.txt  step-16.txt  step-18.txt  step-1.txt  step-3.txt  step-5.txt  step-7.txt  step-9.txt
step-11.txt  step-13.txt  step-15.txt  step-17.txt  step-19.txt  step-2.txt  step-4.txt  step-6.txt  step-8.txt
❯ for f in *.txt; do
newname=$(echo $f | sed 's/txt/md/')
mv $f $newname
done
zsh: command not found: step-10.txt
zsh: command not found: step-11.txt
zsh: command not found: step-12.txt
zsh: command not found: step-13.txt
zsh: command not found: step-14.txt
zsh: command not found: step-15.txt
zsh: command not found: step-16.txt
zsh: command not found: step-17.txt
zsh: command not found: step-18.txt
zsh: command not found: step-19.txt
zsh: command not found: step-1.txt
zsh: command not found: step-2.txt
zsh: command not found: step-3.txt
zsh: command not found: step-4.txt
zsh: command not found: step-5.txt
zsh: command not found: step-6.txt
zsh: command not found: step-7.txt
zsh: command not found: step-8.txt
zsh: command not found: step-9.txt
↵ Error. Exit status 127.
❯ for f in *.txt; do
mv $f $(echo $f | sed 's/txt/md/')
done
❯ ls
step-10.md  step-12.md  step-14.md  step-16.md  step-18.md  step-1.md  step-3.md  step-5.md  step-7.md  step-9.md
step-11.md  step-13.md  step-15.md  step-17.md  step-19.md  step-2.md  step-4.md  step-6.md  step-8.md
 

Почему это работает, когда я помещаю $(echo $f | sed 's/txt/md/') в строку с mv , но не когда она назначена переменной? Почему в нем говорится command not found: $f , когда мой цикл предоставляет $f mv команду в качестве аргумента?

Комментарии:

1. избавьтесь от обратной косой черты в конце строки newname назначения.

Ответ №1:

Эта обратная косая черта означает, что он оценивает

 newname=$(echo $f | sed 's/txt/md/')mv $f $newname
 

который, конечно, рассматривает имя файла как имя выполняемой команды (mv является частью newname переменной).

Вам sed здесь вообще не нужно; просто используйте расширение параметров:

 for f in *.txt; do
    mv "$f" "${f/%txt/md}"
done
 

Существует также несколько различных программ с именами rename ( prename rename.ul , и т.д. в зависимости от операционной системы), Которые могут массово переименовывать файлы; проверьте справочные страницы, какие из них (если таковые имеются) вы установили и используете.

Комментарии:

1. В zsh ${name/pattern/repl} расширении a % в начале шаблона означает, что он совпадает только в конце строки. А # привязывается к началу. #% означает, что шаблон должен соответствовать всей строке; или использовать ${name:/pattern/repl} для того же эффекта.

2. в ${name... том, что мы имеем дело с такой переменной, как $name ?? (синтаксис расширения оболочки часто сбивает меня с толку)

3. и в mv "$f" "${f/%txt/md}" «f» ${f/ есть f, потому что мы имеем дело с переменной с именем $f ?

4. @alec Да. zsh в документации используется имя (а иногда и спецификация ) в разделе о расширении параметров. Это может быть простое имя переменной или строка, являющаяся результатом вложенного расширения, и т.д. В зависимости от того, что вы делаете. В данном случае переменная f .

5. Спасибо. Приятно узнать о функции поиска/замены расширения параметров.