Добавить к имени файла команду find

Добавить к имени файла команду find

Есть ли способ?только с помощью команды findдобавить строку к именам файлов?

Итак, это:

201a.txt
201b.png
...

Становится так:

foo_201a.txt
foo_201b.png
...

Этот:

find . -name '201*' -execdir mv {} foo_{} \;

Не работает, так как {}часть включает начальную часть ./имени файла и поэтому пытается записать в foo_./201*.

Если это невозможно сделать только с помощью find, какой наиболее переносимый (читай: только coreutils, без скриптов оболочки, самый простой для понимания) способ добавить строку к именам файлов?

решение1

Нет. Но renameкоманда предлагает простое решение.

$ ls -1
201a.txt
201b.png
$ rename 201 foo_201 201*
$ ls -1
foo_201a.txt
foo_201b.png
$

решение2

Как насчет

find . -name '201*' -execdir basename {} \; | xargs -I{} mv {} foo_{}

basenameпредоставляется coreutilsи поскольку xargsпредоставляется, findutilsон должен быть по крайней мере таким же переносимым, как и find -execdirон сам.


Альтернативный вариант — использование только функций оболочки POSIX

find . -name '201*' -execdir sh -c 'mv "$1" "foo_${1#*/}"' sh {} \;

решение3

Это невозможно сделать с помощью findодной команды, даже с помощью GNU find. GNU find может печатать файлы с удаленным префиксом командной строки и другим префиксом вместо него, используя -printf foo_%pвместо -print, но для . ничего подобного нет -exec.

(Вы можете использовать find -printf 'mv foo_%p …' | sh, если вам нравится жить опасно. Это работает только с «скромными» именами файлов и ужасно ломается, если в именах файлов есть пробелы, кавычки и другие специальные символы. Так что не делайте этого.)

Стандартный способ сделать это (который работает в любой системе POSIX, а также является общепринятым) — вызвать оболочку для выполнения манипуляций со строками.

find . -name '201*' -exec sh -c 'mv -- "$0" "${0%/*}/foo_${0##*/}"' {} \;

Я не использую, -execdirпотому что это расширение GNU, а вы просили о переносимости. Обратите внимание, что это {}передается оболочке как аргумент. Никогда не используйте {}внутри кода оболочки: не только потому, что это непереносимо, но, что самое важное, потому что это приведет к интерпретации имени файла как кода оболочки, что не сработает, если имя файла содержит специальные символы.

В современных системах POSIX (любых из последнего десятилетия) можно немного ускорить выполнение этой команды, объединив вызовы оболочки.

find . -name '201*' -exec sh -c 'for x do mv -- "$x" "${x%/*}/foo_${x##*/}"; done' sh {} +

В качестве альтернативы в ksh, bash или zsh можно использовать рекурсивную подстановку вместо вызова find.

set -o globstar # ksh only
shopt -s globstar # bash only
for x in **/201*; do
  mv -- "$x" "${x%/*}/foo_${x##*/}"
done

решение4

Вместо этого можно использовать звездочку ( *), которая удаляет ./часть:

find * -name '201*' -exec mv {} foo_{} \;  

Связанный контент