recursively rename directories in bash

Try the following code using parameter expansion

find . -type d -iname '*foo*' -depth -exec bash -c '
    echo mv "$1" "${1//[Ff][Oo][Oo]/BAr}"
' -- {} \;

But your best bet will be the prename command (sometimes named rename or file-rename)

find . -type d -iname '*foo*' -depth -exec rename 's@Foo@Bar@gi' {} +

And if you are using bash4 or zsh (** mean recursive):

shopt -s globstar
rename -n 's@Foo@Bar@gi' **/*foo*/

If it fit your needs, remove the -n (dry run) switch to rename for real.

SOME DOC

rename was originally written by Perl's dad, Larry Wall himself.


I suspect the problem is getting it to work with mkdir -p foo/foo/foo.

In this regard, I think a solution based on find will likely not work because the list of paths is probably predetermined.

The following is in no way elegant, and stretches the definition of a one-liner, but works for the above test.

$ 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

find . -type d -iname '*foo*' -exec bash -O nocasematch -c \
    '[[ $1 =~ (foo) ]] && mv "$1" "${1//${BASH_REMATCH[1]}/Bar}"' -- {} \;

Pro: Avoids sed.
Con: Will not find all matches if there are multiple in different cases.
Con: Is ridiculous.

Tags:

Bash