Передача имен файлов в zmv

Я считаю, что гораздо проще использовать find и затем grep -v в конвейере для фильтрации файлов вместо разработки сложных шаблонов регулярных выражений. Однако, когда я передаю что-то в zmv, вот так:

find | grep -v TFLM | zmv "(*)" "TFLM \$1" 

Он просто игнорирует ввод и продолжает применять преобразование ко всем файлам. Есть ли способ сказать ему, чтобы использовать вход трубы? Я думаю, я мог бы удалить отфильтрованные файлы и затем использовать zmv, но это не совсем решение.

То, что вы делаете, это не то, как find , grep и zmv предназначены для работы. Сначала вы используете find для поиска файлов, а затем grep для шаблона; это не имеет никакого смысла. Команда find имеет встроенное сопоставление с образцом, например, в GNU find начиная с базовых -name до -iname , -iname , -regex и многих других. Вы можете даже изменить синтаксис для регулярного выражения, если вы предпочитаете, с помощью -regextype . Дело не только в том, что вы делаете что-то не так быстро или слишком много команд, но хуже всего то, что ваша команда подвержена ошибкам, например, если в файле есть место внутри.

Намного лучше просто find с параметром -exec за которым следует внешняя команда, такая как mv . С некоторой осторожностью это решение может быть очень переносимым в разных системах.

Но, так как вы используете zsh он просит использовать всю его славу, поэтому просто добавьте опцию zmv в zmv и поэкспериментируйте с различными шаблонами, скорее всего, вы захотите

 zmv -vn '(^(*TFLM*))' 'TFLM $1' 

-v означает многословный, а -n предотвращает выполнение, просто печатает, что будет сделано (это отлично подходит для тестирования).

zmv не читает со стандартного ввода.

Я бы, вероятно, использовал здесь find с mv или zmv с глобусом имени файла zsh , но не оба, и вообще без участия grep . Использование grep должно быть сделано для текста, который разделен на строки, а не на имена файлов (которые могут включать встроенные символы новой строки).

С именами глобусов (будет действовать только на текущий каталог и только на не скрытые файлы):

 zmv '^TFLM *' 'TFLM $f' 

Рекурсивно, не переименовывать каталоги, включая скрытые файлы и файлы в скрытых каталогах, как find :

 zmv '(**/)(^TFLM *)(#qD^/)' '${1}TFLM $2' 

С помощью find (но без обработки конфликтов в zmv , поэтому добавив опцию -i для безопасности):

 find . ! -type d ! -name 'TFLM *' -exec sh -c ' for pathname do mv -i "$pathname" "${pathname%/*}/TFLM ${pathname##*/}" done' sh {} + 

В bash (только для текущего каталога, исключая скрытые файлы):

 shopt -s extglob for name in !(TFLM *); do mv -i -- "$name" "TFLM $name" done 

Или в bash с помощью утилиты rename Perl:

 shopt -s extglob rename 's|/|/TFLM |' ./!(TFLM *) 

(без ./ , некоторые варианты потерпели бы неудачу, если бы были имена файлов, начинающиеся с - . Поддерживаются не все варианты -- чтобы отметить конец параметров).

Я мысленно работаю так же, как и вы, где я предпочитаю наслоение команд grep до конца. Трудно противостоять побуждению, но в таких ситуациях вы должны или мысленно помнить об этом, когда хотите начать действовать в списке из find | ... find | ... что ты должен начать тянуть в xargs . Когда вы дойдете до этого момента, пришло время переключиться, чтобы find -exec ...

В вашем сценарии шаблон, который вы могли бы рассмотреть здесь, выглядит примерно так:

 $ find . ! -name "*TFLM*" -exec zmv "{}" "TFLM {}" \; 

Но это не будет работать, согласно комментариям @StephaneChazelas:

Поскольку zmv является функцией zsh, она не может быть выполнена напрямую с помощью find. Даже если бы кто-то создавал автономную оболочку для скриптов вокруг zmv, называя ее так -exec zmv “{}” … не было бы особого смысла (полностью отказавшись от цели zmv) и привел бы к уязвимости внедрения команд

Таким образом, у вас остались более традиционные варианты использования одного из методов, показанных в этом разделе вопросов и ответов под названием « Пакетное переименование файлов» .

Или используя zmv напрямую для переименования. Поскольку вы используете zsh и zmv , скорее всего, вам даже не нужно zmv за помощью к find .

 $ zmv "(^*TFLM*)" "TFLM \$1" 

ПРИМЕЧАНИЕ: примите мой совет по zmv и zsh с зерном соли. Я на самом деле не использую Zsh, я обычно нахожусь в Bash весь день.

Рекомендации

  • zmv – это функция zsh для переименования файлов.