外壳脚本内部编码与重定向输出不同



目前我正在处理一堆旧文件,这些文件在其生命周期中见过很多机器、操作系统和文件系统。其中有几个包含德语元音变音符(ä,ö,ü(,显然这些导致一些文件名在一个移动过程中中断。一个最初名为的文件

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

我正在努力理解:

  1. 为什么屏幕输出与文件中的不同?角色替换在哪里发生,问号在哪里产生
  2. 如何防止在脚本过程中使用问号来解释非法字符?它防止我有选择地用相应的正确字符替换非法字符

问号替换可能发生在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码,以八进制表示(。

最新更新