Рекурсивно переименовывать каталоги в bash
Я бы хотел рекурсивно переименовать все каталоги, содержащие строку foo, заменив эту часть строки на Bar. У меня есть что-то подобное до сих пор, но это не работает. Мне также хотелось бы, чтобы foo искался без учета регистра.
find . -type d -exec bash -c 'mv "$1" "${1//foo/Bar}"' -- {} \;
Есть ли элегантные однострочные линии, которые могут быть лучше, чем эта попытка? Я на самом деле попробовал несколько, но думал, что буду откладывать на экспертов. Примечание: я делаю это в системе Mac OS X и не имею таких инструментов, как rename.
Ответы
Ответ 1
Попробуйте использовать следующий код с расширением параметра
find . -type d -iname '*foo*' -depth -exec bash -c '
echo mv "$1" "${1//[Ff][Oo][Oo]/BAr}"
' -- {} \;
Но лучшим вариантом будет команда prename
(иногда называемая rename
или file-rename
)
find . -type d -iname '*foo*' -depth -exec rename '[email protected]@[email protected]' {} +
И если вы используете bash4
или zsh
(**
означает рекурсивный):
shopt -s globstar
rename -n '[email protected]@[email protected]' **/*foo*/
Если это соответствует вашим потребностям, удалите переключатель -n
(сухой режим) для переименования для реального.
НЕКОТОРЫЕ DOC
rename изначально был написан отцом Перла, самого Ларри Уэлла.
Ответ 2
Я подозреваю, что проблема заключается в том, чтобы заставить его работать с mkdir -p foo/foo/foo
.
В этом отношении я думаю, что решение, основанное на find
, скорее всего, не сработает, потому что список путей, вероятно, предопределен.
Следующее не является элегантным и растягивает определение однострочного слоя, но работает для вышеуказанного теста.
$ mkdir -p foo/foo/foo
$ (shopt -s nullglob && _() { for P in "$1"*/; do Q="${P//[Ff][Oo][Oo]/bar}"; mv -- "$P" "$Q"; _ "$Q"; done } && _ ./)
$ find
.
./bar
./bar/bar
./bar/bar/bar
Ответ 3
find . -type d -iname '*foo*' -exec bash -O nocasematch -c \
'[[ $1 =~ (foo) ]] && mv "$1" "${1//${BASH_REMATCH[1]}/Bar}"' -- {} \;
Pro: Avoids sed.
Кон: Не будет найдено совпадений, если в разных случаях несколько.
Кон: Смешно.
Ответ 4
Я искал похожие ответы, и это работало:
find . -depth -name 'foo' -execdir bash -c 'mv "$0" ${0//foo/Bar}"' {} \;
Ответ 5
Спасибо @Gilles Quenot и Wenli: у меня сработало следующее. Я основал это на обоих ваших решениях.
find . -depth -type d -name 'ReplaceMe*' -execdir bash -c 'mv "$1" "${1/ReplaceMe/ReplaceWith}"' -- {} \;
-execdir
, кажется, является ключевым в Linux Red Hat 7,6