目前我正在处理一堆旧文件,这些文件在其生命周期中见过很多机器、操作系统和文件系统。其中有几个包含德语元音变音符(ä,ö,ü(,显然这些导致一些文件名在一个移动过程中中断。一个最初名为的文件
München.txt
显示为
M?nchen.txt (invalid encoding)
在ubuntu系统上,它们当前所在的位置。
所以现在我正试着批量修复它们。在循环浏览带有初稿的文件时,我偶然发现了这种现象:
返回屏幕会给我带问号的文件名,我知道这是对文件名中非法字符的解释:
./list_files.sh path_to_files M?nchen.txt K?ln.txt
但是,如果我将输出保存到一个文件中,它会给我一个仍然包含无效字符的二进制文件:
./list_files.sh path_to_files > file_list less file_list M<FC>nchen.txt K<F6>ln.txt
这是代码:
#!/bin/bash
rootdir=$1
find "$rootdir" -print0 | while IFS= read -r -d '' broken_file_name; do
echo $broken_file_name
done
我正在努力理解:
- 为什么屏幕输出与文件中的不同?角色替换在哪里发生,问号在哪里产生
- 如何防止在脚本过程中使用问号来解释非法字符?它防止我有选择地用相应的正确字符替换非法字符
问号替换可能发生在Bash本身,只要您使用Bashecho
并尝试输出在当前语言环境中无法表示的字符。它也可能是终端驱动程序的一个功能。
我们只能推测原始编码,但症状与Latin-1(ISO-8859-1(一致。
假设我猜对了编码,并且假设您当前的语言环境是UTF-8语言环境,请尝试类似的方法
while IFS= read -r original; do
dest=$(iconv -f iso-8859-1 <<<"$original")
mv -- "$original" "$dest"
done <file_list
less
的不同行为可能是less
的事情。来自手册:
控制和二进制字符以突出显示(反向视频(。如果可能的话,每个这样的字符都以插入符号表示法显示(例如^A代表control-A(。只有当将0100位反转为正常可打印字符时,才使用Caret表示法。否则,字符将显示为尖括号中的十六进制数字。可以通过设置LESSBINFMT环境变量来更改此格式。
但由于您想要的是重命名文件,因此各种实用程序显示名称的方式并不那么重要。在脚本中,您可以使用例如tr
来计算新名称,方法是将您不喜欢的字符替换为其他字符。例如,如果您想用o和u分别替换ö和ü:
new=$(tr '366374' 'ou' <<< "$old")
if [ "$new" != "$old" ]; then
mv "$old" "$new"
fi
(366和374是ö和ü的ascii码,以八进制表示(。