Home > Back-end >  How can i find and rename multiple files
How can i find and rename multiple files

Time:05-19

I have multiple files in multiple directories and i have to rename these files from lowercase to uppercase; the file extension may vary and needs to be in lowercase (should be renamed too for files with extensions in uppercase).

NB: I have rename version from util-linux on CentOS Linux7.

i tried this :

find /mydir -depth | xargs -n 1 rename -v 's/(.*)\/([^\/]*)/$1\/\U$2/' {} \;
find /mydir -depth | xargs -n 1 rename -v 's/(.*)\/([^\/]*)/$2\/\L$2/' {} \;

but it's not working it changes nothing and i have no output.

Itried another solution :

for SRC in `find my_root_dir -depth`
do
   DST=`dirname "${SRC}"`/`basename "${SRC}" | tr '[A-Z]' '[a-z]'`
   if [ "${SRC}" != "${DST}" ]
   then
      [ ! -e "${DST}" ] && mv -T "${SRC}" "${DST}" || echo "${SRC} was not renamed"
   fi
done

this one partially works but transforms the files extensions to uppercase too.

Any suggestions on how to keep/transform the extensions to lowercase ?

Thank you!

CodePudding user response:

rename-independent solution (using find together with mv)

You can rename all files in a directory with a following command:

for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done

First part (for i in $( ls | grep [A-Z] );) looks for all uppercase characters and executes until all files are "scanned".

Second part (``) turns all uppercase characters into lowercase ones.


Perl-based rename dependent solution

rename -f 'y/A-Z/a-z/' *

This command changes uppercase characters to the lowercase ones. -f option allows overwriting of existing files, but it is not necessary.

CodePudding user response:

Possible solution with Perl rename:

find /mydir -depth -type f -exec rename -v 's/(.*\/)?([^.]*)/$1\U$2/' {}  

The commands in the question have several problems.

You seem to confuse the syntax of find's -exec action and xargs.

find /mydir -depth -type f -exec rename -v 'substitution_command' {} \;
find /mydir -depth -type f| xargs -n 1 rename -v 'substitution_command'

The xargs version has problems in case a file name contains a space.

If you replace \; with , multiple file names are passed to one invocation of rename.


The substitution command is only supported by the Perl version of the rename command. You might have to install this version. See Get the Perl rename utility instead of the built-in rename


The substitution did not work in my test. I successfully used

rename -v 's/(.*\/)?([^.]*)/$1\U$2/' file ...

The first group (.*\/)? optionally matches a sequence of characters with a trailing /. This is used unchanged.

The second group ([^.]*) matches a sequence of characters except ..

This converts the file name part before the first dot (if any) to uppercase. In case the file name has more than one extension, all will remain unchanged, e.g.
Path/To/Foo.Bar.Baz -> Path/To/FOO.Bar.Baz

CodePudding user response:

suggesting a trick with awk that will generate all required mv commands:

awk '{f=$0;split($NF,a,".");$NF=tolower(a[1])"."toupper(a[2]);print "mv "f" "$0}' FS=/ OFS=/ <<< $(find . -type f)

Inspect the result, and run all mv commands together:

bash <<< $(awk '{f=$0;split($NF,a,".");$NF=tolower(a[1])"."toupper(a[2]);print "mv "f" "$0}' FS=/ OFS=/ <<< $(find . -type f))

awk script script.awk explanation

BEGIN { # preprocessing configuration
  FS="/"; # set awk field separtor to /
  OFS="/"; # set awk output field separtor to /
}
{ # for each line in input list
  filePath = $0; # save the whole filePath in variable
  # fileName is contained in last field $NF
  # split fileName by "." to head: splitedFileNameArr[1] and tail: splitedFileNameArr[2]
  split($NF,splitedFileNameArr,"."); 
  # recreate fileName from lowercase(head) "." uppercase(tail)
  $NF = tolower(splitedFileNameArr[1]) "." toupper(splitedFileNameArr[2]);
  # generate a "mv" command from original filePath and regenerated fileName
  print "mv "filePath" "$0; 
}

Testing:

mkdir {a1,B2}/{A1,b2} -p; touch {a1,B2}/{A1,b2}/{A,b}{b,C}.{c,D}{d,C}
find . -type f

./a1/A1/Ab.cC
./a1/A1/Ab.cd
./a1/A1/Ab.DC
./a1/A1/Ab.Dd
./B2/b2/AC.DC
./B2/b2/AC.Dd
.....
./B2/b2/bC.cd
./B2/b2/bC.DC
./B2/b2/bC.Dd

awk -f script.awk <<< $(find . -type f)

.....
mv ./a1/b2/Ab.cd ./a1/b2/ab.CD
mv ./a1/b2/Ab.DC ./a1/b2/ab.DC
mv ./a1/b2/Ab.Dd ./a1/b2/ab.DD
mv ./B2/A1/bC.Dd ./B2/A1/bc.DD
.....
mv ./B2/b2/bC.DC ./B2/b2/bc.DC
mv ./B2/b2/bC.Dd ./B2/b2/bc.DD

bash <<< $(awk -f script.awk <<< $(find . -type f))
find . -type f
  • Related