如何从 Bash 中使用 iconv 递归重命名文件和文件夹

问题描述 投票:0回答:2

我一直在尝试使用 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)"' -- {} \;

原来的问题: 我只是想批量重命名大量文件,使它们“网络友好”,比如删除空格、奇怪的字符等等,目前我有

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

linux file bash iconv tr
2个回答
3
投票

我认为以下内容一次性完成了您想要的一切。

# 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
投票

这是我在 chepner 的回答之后提供的更新,以避免嵌套错误。使用

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

享受;)

© www.soinside.com 2019 - 2024. All rights reserved.