sed: Rename files to lower case

1 
1 7.4 Rename Files to Lower Case
1 ==============================
1 
1 This is a pretty strange use of 'sed'.  We transform text, and transform
1 it to be shell commands, then just feed them to shell.  Don't worry,
1 even worse hacks are done when using 'sed'; I have seen a script
1 converting the output of 'date' into a 'bc' program!
1 
1    The main body of this is the 'sed' script, which remaps the name from
1 lower to upper (or vice-versa) and even checks out if the remapped name
1 is the same as the original name.  Note how the script is parameterized
1 using shell variables and proper quoting.
1 
1      #! /bin/sh
1      # rename files to lower/upper case...
1      #
1      # usage:
1      #    move-to-lower *
1      #    move-to-upper *
1      # or
1      #    move-to-lower -R .
1      #    move-to-upper -R .
1      #
1 
1      help()
1      {
1              cat << eof
1      Usage: $0 [-n] [-r] [-h] files...
1 
1      -n      do nothing, only see what would be done
1      -R      recursive (use find)
1      -h      this message
1      files   files to remap to lower case
1 
1      Examples:
1             $0 -n *        (see if everything is ok, then...)
1             $0 *
1 
1             $0 -R .
1 
1      eof
1      }
1 
1      apply_cmd='sh'
1      finder='echo "$@" | tr " " "\n"'
1      files_only=
1 
1      while :
1      do
1          case "$1" in
1              -n) apply_cmd='cat' ;;
1              -R) finder='find "$@" -type f';;
1              -h) help ; exit 1 ;;
1              *) break ;;
1          esac
1          shift
1      done
1 
1      if [ -z "$1" ]; then
1              echo Usage: $0 [-h] [-n] [-r] files...
1              exit 1
1      fi
1 
1      LOWER='abcdefghijklmnopqrstuvwxyz'
1      UPPER='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
1 
1      case `basename $0` in
1              *upper*) TO=$UPPER; FROM=$LOWER ;;
1              *)       FROM=$UPPER; TO=$LOWER ;;
1      esac
1 
1      eval $finder | sed -n '
1 
1      # remove all trailing slashes
1      s/\/*$//
1 
1      # add ./ if there is no path, only a filename
1      /\//! s/^/.\//
1 
1      # save path+filename
1      h
1 
1      # remove path
1      s/.*\///
1 
1      # do conversion only on filename
1      y/'$FROM'/'$TO'/
1 
1      # now line contains original path+file, while
1      # hold space contains the new filename
1      x
1 
1      # add converted file name to line, which now contains
1      # path/file-name\nconverted-file-name
1      G
1 
1      # check if converted file name is equal to original file name,
1      # if it is, do not print anything
1      /^.*\/\(.*\)\n\1/b
1 
1      # escape special characters for the shell
1      s/["$`\\]/\\&/g
1 
1      # now, transform path/fromfile\n, into
1      # mv path/fromfile path/tofile and print it
1      s/^\(.*\/\)\(.*\)\n\(.*\)$/mv "\1\2" "\1\3"/p
1 
1      ' | $apply_cmd
1