Есть ли способ?только с помощью команды 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_{} \;