skip to Main Content

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!

3

Answers


  1. 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.

    Login or Signup to reply.
  2. Possible solution with Perl rename:

    find /mydir -depth -type f -exec rename -v 's/(.*/)?([^.]*)/$1U$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/(.*/)?([^.]*)/$1U$2/' file ...
    

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

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

    This is the file name part before the first dot (if any) which will be converted 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

    Login or Signup to reply.
  3. 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
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search