Change file names with find and iconv

wisent picture wisent · Mar 29, 2012 · Viewed 9k times · Source

I've tried to change filenames using following script:

find dir/ -type f -exec mv {} $(echo {} | iconv -f UTF8 -t ASCII//TRANSLIT ) \;

Why doesn't it work? I mean when I have a file with character like 'ą' it should convert it to 'a'.

$ echo ążźćó | iconv -f UTF8 -t ASCII//TRANSLIT
azzco

why does it not work in find -exec?

$ find dir/ -type f -exec mv {} $(echo {} | iconv -f UTF8 -t ASCII//TRANSLIT ) \;
mv: `dir/zią' and `dir/zią' are the same file

I get the same results using xargs:

$ find dir/ -type f | xargs -I{} echo {} | iconv -f UTF8 -t ASCII//TRANSLIT
dir/zia

but:

$ find dir/ -type f | xargs -I{} mv {} $(echo {} | iconv -f UTF8 -t ASCII//TRANSLIT)
mv: `dir/zią' and `dir/zią' are the same file

Answer

FatalError picture FatalError · Mar 29, 2012

The problem with using $() in this way is that the subshell executes prior to executing the find command, and not as part of -exec. You can do it, but you'll need to invoke bash. Something like:

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

Keep in mind this will also translit any special chars in directory names as well, which may cause the mv to fail. If you only want to translit the filename, then you could:

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

which split the directory portion off and only translits the file name.