. *
соответствует все в остальной части строки, поэтому все заменено. Если вы хотите заменить все до следующего пробела, вам понадобится [^] вместо
.`
Как насчет
find . -name '201*' -execdir basename {} \; | xargs -I{} mv {} foo_{}
базовое имя
предоставляется coreutils
, а поскольку xargs
предоставляется findutils
он должен быть не менее переносимым, чем сам find -execdir
.
В качестве альтернативы, использование только функций оболочки POSIX
find . -name '201*' -execdir sh -c 'mv "$1" "foo_${1#*/}"' sh {} \;
Нет. Но команда rename
предлагает простое решение.
$ ls -1
201a.txt
201b.png
$ rename 201 foo_201 201*
$ ls -1
foo_201a.txt
foo_201b.png
$
Вместо этого можно использовать звездочку (*
), которая удаляет часть ./
:
find * -name '201*' -exec mv {} foo_{} \;
В GNU Parallel это выглядит так:
# Make an annoying dir and a couple of annoying files
mkdir '"*'" '"
touch '"*'" '"/201'"*'" '".txt
touch '"*'" '"/201'"*'" '".png
# GNU Parallel deals nicely with annoying files
find . -name '201*' | parallel mv {} {//}/foo_{/}
Это невозможно только с find
, даже с GNU find. GNU find может печатать файлы с удаленным префиксом командной строки и добавленным вместо него другим префиксом, используя -printf foo_%p
вместо -print
, но нет ничего подобного для - исполнить
.
(Вы можете использовать find -printf 'mv foo_%p …' | sh
, если вам нравится жить опасно. Это работает только с «ручными» именами файлов и ужасно ломается, если есть пробелы, кавычки и другие специальные символы в именах файлов. Так что не делайте этого.)
Стандартный способ сделать это (работающий в любой системе POSIX, а также общепринятый способ) — вызвать shell для выполнения манипуляций со строками.
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