linuxfilebashiconvtr

How to recursively rename files and folder with iconv from Bash


I have been trying to recursively rename files AND folders with iconv without success, the files are correctly renamed but folders dont.

What I use for files is (works perfect):

find . -name * -depth \ -exec bash -c 'mv "$1" "${1%/*}/$(iconv -f UTF8 -t ASCII//TRANSLIT <<< ${1##*/})"' -- {} \;

What I tried for files AND folders (fail: Only rename folders):

find . -exec bash -c 'mv "$1" "$(iconv -f UTF8 -t ASCII//TRANSLIT <<< $1)"' -- {} \;

ORIGINAL problem: I just want to bulk rename lots of files to make them "web friendly", thinks like removing spaces, weird characters and so on, currently I have

find . -name '*' -depth \
| while read f ; 
do 
mv -i "$f" "$(dirname "$f")/$(basename "$f"|tr -s ' ' _|tr -d "'"|tr -d ","|tr - _|tr "&" "y"|tr "@" "a")" ;
done 

Is there any way to do the tr stuff above and the iconv at a single run? because I am talking around 300,000 files to rename, I would like to avoid a second search if possible.

If needed, I am working with Bash 4.2.24


Solution

  • I think the following does everything you want in one pass.

    # Update: if this doesn't work, use read -d '' instead
    find . -print0 | while IFS= read -d '$\000' f ;
    do 
      orig_f="$f"
      # Below is pure bash. You can replace with tr if you like
      # f="$( echo $f | tr -d ,\' | tr "$'&'@- " "ya__" )"
      f="${f// /_}"  # Replace spaces with _
      f="${f//\'}"   # Remove single quote
      f="${f//-/_}"  # Replace - with _
      f="${f//,}"    # Remove commas
      f="${f//&/y}"  # Replace ampersand with y
      f="${f//@/a}"  # Replace at sign with a
      f=$( iconv -f UTF8 -t ASCII//TRANSLIT <<< "$f" )
      new_dir="$(dirname $f)"
      new_f="$(basename $f)"
      mkdir -p "$new_dir"
      mv -i "$orig_f" "$new_dir/$new_f"
    done 
    

    The find command (no real options needed, other than -print0 to handle filenames with spaces) will send null-separated file names to the while loop (and someone will correct my errors there, no doubt). A long list of assignments utilizing parameter expansion removes/replaces various characters; I include what I think is the equivalent pipeline using tr as a comment. Then we run the filename through iconv to deal with character set issues. Finally, we split the name into its path and filename components, since we may have to make a new directory before executing the mv.