Update: Added a version which can handle any/all valid filename characters, except for \x01
, which is used as sed's delimiter.... I have used A.*
as the pattern in the updated examples, because I was testing for A"'
. Of course, just change to whatever you need.
findx="\(.*/\)\(A.* \)\([0-9]\)$"
replx="&\x00\1\20\3\x00"; I=$'\x01'
find . -depth -type d -regex "$findx" |
sed -n "s$I$findx$I$replx$I p" |
tr -d '\n' |
xargs --verbose -0n2 mv
Here is an example, using perl
instead of sed
.
Note that perl's regualar expressions PCRE
are not entirely the same as posix-extended ERE
as used by find
in this example. They do, however, share enough in common that the same regex pattern can be used in this case.
export findx='(.*/)(A.* )([0-9])$'
find . -depth -type d -regextype posix-extended -regex "$findx" |
perl -l000pe 's/$ENV{'findx'}/$_\000$1${2}0$3/' |
xargs --verbose -0n2 mv
These next versions cannot handle single-quotes '
in filenames.
Using standard regex patterns
regex='\(.*/\)\(A \)\([0-9]\)$'
find . -depth -type d -regex "$regex" |
sed -n "s|$regex|'&' '\1\20\3'|p" |
xargs --verbose -n2 mv
To use extended regex paterns
regex='(.*/)(A )([0-9])$'
find . -depth -regextype posix-extended -type d -regex "$regex" |
sed -nr "s|$regex|'&' '\1\20\3'|p" |
xargs --verbose -n2 mv
The -depth
option is needed so that more deeply nested directories are renamed before any parent directory is renamed.
Note that the script does not test if a directory already exists with the same name as the new intended name.
Thank you very much, this works well except in a case where a ' (single quote) character is in the name. Any idea how to tell sed or xargs to escape critical characters? You don't happen to spot the error in my command using -execdir? Using xargs like you did looks much easier and clearer, but I would like to understand what's going on. – slosd – 2012-08-12T09:58:28.637
Your regex was basically on track, but when you start needing to echo into an echo, I find there is often another way by using a straightt pipe-line. I have added a version which caters for single and/or double quotes and any other valid character other than
\x01
, which is used as sed's delimiter, and\x00
which is not valid in *nix filenames. Quoting the file paths is nott needed if you usexargs
with the-0, --null
option as an arg-separator.. I've added an extratr
step to remove the spurious\n
which sed needs. If you useperl
instead ofsed
you could avoid this step. – Peter.O – 2012-08-12T18:29:32.697Note that
-execdir
changes the working directory to the parent directory for each path being processed. This means that you do not need to use fully-qualified paths. But, on its own, it does not produce a-depth
listing with deeper level directories before their parents. If you have/abc/A 1/B 2/
and/abc/A 1
is renamed first, then depending on howfind
handles its buffering, it may try to rename/abc/A 1/B 2
, but that no longer exists! ... so, for this situation use-depth
. – Peter.O – 2012-08-13T09:42:35.707Thanks for the great effort. I must say the shell is a minefield when it comes to file renaming stuff like this. Next time I will use some higher-level language... ;) – slosd – 2012-08-14T17:24:44.153