如何使用来自Bash的iconv递归重命名文件和文件夹

时间:2012-07-17 20:23:50

标签: linux file bash iconv tr

我一直试图用iconv递归重命名文件和文件夹但没有成功,文件被正确重命名但文件夹没有。

我用于文件的是(完美的):

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

我尝试过的文件和文件夹(失败:只重命名文件夹):

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

原始问题: 我只是想批量重命名大量文件,使它们“对Web友好”,想像删除空格,奇怪的字符等等,目前我已经

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 

有没有办法在一次运行中执行上面的tr和iconv?因为我正在谈论要重命名的300,000个文件,我想尽可能避免第二次搜索。

如果需要,我正在使用Bash 4.2.24

提前致谢。

2 个答案:

答案 0 :(得分:2)

我认为以下内容可以在一次通过中完成您想要的一切。

# 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 

find命令(除-print0以外不需要实际选项来处理带空格的文件名)会将空值分隔的文件名发送到while循环(有人会更正我的那里的错误,毫无疑问)。利用参数扩展的一长串分配删除/替换各种字符;我使用tr作为注释包含我认为是等效管道的内容。然后我们通过iconv运行文件名来处理字符集问题。最后,我们将名称拆分为路径和文件名组件,因为我们可能必须在执行mv之前创建一个新目录。

答案 1 :(得分:0)

以下是我在chepner's answer之后提供的更新,以避免嵌套错误。使用find反转tac的输出,以便在文件夹本身之前对文件夹内容执行操作。这样,就不再需要mkdir

echo "renaming:"
find . -print0 | tac -s '' | while IFS= read -d '' f ;
do
    Odir=$(dirname "$f")   # original location
    Ofile=$(basename "$f") # original filename
    newFile=$Ofile
    # remove unwanted characters
    newFile=$(echo $newFile | tr -d ",'\"?()[]{}\\!")
    newFile="${newFile// /_}"  # Replace spaces with _
    newFile="${newFile//&/n}"  # Replace ampersand with n
    newFile="${newFile//@/a}"  # Replace at sign with a
    newFile=$( iconv -f UTF8 -t ASCII//TRANSLIT <<< "$newFile" )
    if [[ "$Ofile" != "$newFile" ]]; then # act if something has changed
      echo "$Odir/$Ofile to"
      echo "$Odir/$newFile"
      mv -i "$Odir/$Ofile" "$Odir/$newFile"
      echo ""
    fi
done
echo "done."

享受;)