我有一个 bash 脚本来比较不同位置的文件名。它们的文件名中有特殊字符,采用两种不同的编码,因此我的脚本与这些特定文件不匹配。
我能做些什么让 bash 匹配它们吗?
它们分别编码为 utf8 和 TIS-620 示例文件名Löffler
,以及Löffler
脚本示例:
for i in /dir1/*; do
if [ ! -h "$i" ]; then
[ -d "/dir2/${i##*/}" ]
fi
使用乌努姆我可以得到这些信息:
ö 的 utf8 版本
Octal Decimal Hex HTML Character Unicode
0366 246 0xF6 ö "ö" LATIN SMALL LETTER O WITH DIAERESIS
TIS-620版ö
Octal Decimal Hex HTML Character Unicode
0157 111 0x6F o "o" LATIN SMALL LETTER O
01410 776 0x308 ̈ "̈" COMBINING DIAERESIS
编辑:
我首先找出了导致不匹配的原因,这是一个使用 UTF 标准化的工具。我还是想知道如何匹配不同编码中的相同字符。另一种说法是,如何对 BASH 脚本内联使用 UTF 规范化?
答案1
我认为您需要比较编码中的一些“文本”TIS-620 的代码页(泰语)与utf8编码(通用)等效。
好吧,由于最通用的编码(它将编码与 UTF-32 一样多的字符)是 utf8,我们应该将最本地的编码 TIS-620 转换为它。
常用的编码转换工具是iconv
。使用该工具,您可以执行以下操作:
$ printf '\xC1' | iconv -f TIS620 -t utf8
ม
并查看(如果您的终端接受 utf8)字符 ม。该角色ม
的值可以C1
查看维基百科的 TIS-620 中的表格。
或者,“查看”构成该字符的字节(以 utf8 格式):
$ printf '\xC1' | iconv -f TIS620 -t utf8 | od -vAn -tx1
e0 b8 a1
使用 Unicode 代码点编号对字符进行编码时产生的 3 个字节是多少U0E21
从文件格式或者,也网址:www.utf8-chartable.de:
U+0E21 ม e0 b8 a1 THAI CHARACTER MO MA
iconv 中 TIS620 可用的编码列表为:
$ iconv -l | grep 620
TIS-620//
TIS620-0//
TIS620.2529-1//
TIS620.2533-0//
TIS620//
选择与您的文件名编码相匹配的一种。
但是,我找不到元音变音 ö泰语。
这泰国TIS620页面
或者甚至是(非常古老的)泰语翻译为 ISO/IEC 10646-1:1993不要显示泰语中存在带元音变音的 o。
您能重新编辑您的问题吗?
关于元音变音
假设控制台/终端配置为理解 utf8。并且,让我们在一个目录中创建三个具有不同变音符号的文件名。
拉丁语 ö (作为一个 unicode 代码点)(在 utf8 中表示为 0xC3 0xB6)。
带分音符的拉丁文小写字母 O (U+00F6)
拉丁语 ö$ printf 'L\xC3\xB6ffler'; echo Löffler
拉丁语 ö (字母 o 后跟分音符)(在 utf8 中为 0x6F 0xCC 0x88)。
组合分音法 (U+0308)
分音$ printf 'Lo\xCC\x88ffler'; echo Löffler
并且:带分音符的西里尔字母 o(在 utf-8 中为 0xD3 0xA7)
带分音符的西里尔小写字母 O (U+04E7)
带有分音符的西里尔字母 O$ printf 'L\xD3\xA7ffler'; echo Lӧffler
要使用这些文件名创建三个文件,您可以使用:
$ touch $(printf 'L\xC3\xB6ffler Lo\xCC\x88ffler L\xD3\xA7ffler')
列出此类文件的一种方法是使用匹配的 Glob(仅那些文件)。
在这种情况下,尾随ffler
会出现在所有文件上。
$ echo *ffler
Löffler Löffler Lӧffler
可以通过以下方式详细查看该回波的结果:
$ echo *ffler | od -vAn -tx1c
4c 6f cc 88 66 66 6c 65 72 20 4c c3 b6 66 66 6c
L o 314 210 f f l e r L 303 266 f f l
65 72 20 4c d3 a7 66 66 6c 65 72 0a
e r L 323 247 f f l e r \n
这只是反映了每个人都是不同的事实。
如果它们被分配给 shell 的位置参数:
$ set -- $(echo *ffler)
我们可以对每一项进行比较:
[ "$1" == "$2" ] && echo "Diferent" || echo "Equal"
然而,可以合理地预期第一个和第二个是等效的。
但它们的不同之处在于“构图”的完成方式。
使用'L\xC3\xB6ffler'
NFC(组合)形式。
使用'Lo\xCC\x88ffler'
NFD(分解)形式。
您可以使用 uconv (来自 icu-devtools 包)在这两种形式之间进行转换。
分解形式:
$ echo *ffler | uconv -x any-nfd | od -vAn -tx1c
4c 6f cc 88 66 66 6c 65 72 20 4c 6f cc 88 66 66
L o 314 210 f f l e r L o 314 210 f f
6c 65 72 20 4c d0 be cc 88 66 66 6c 65 72 0a
l e r L 320 276 314 210 f f l e r \n
以预先组合的形式:
$ echo *ffler | uconv -x any-nfc | od -vAn -tx1c
4c c3 b6 66 66 6c 65 72 20 4c c3 b6 66 66 6c 65
L 303 266 f f l e r L 303 266 f f l e
72 20 4c d3 a7 66 66 6c 65 72 0a
r L 323 247 f f l e r \n
现在,如果我们将这些值设置为位置参数并比较它们:
$ set -- $( echo *ffler | uconv -x any-nfc | od -vAn -tx1c )
$ [ "$1" == "$2" ] && echo "Diferent" || echo "Equal"
cyrylic 特征并不等同于任何这种构图形式。
如果您需要转换它,以便可以将该名称与其他名称进行比较,则需要一个能够理解多字节字符的工具。
$ echo *ffler | sed 's/\xd3\xa7/\xc3\xb6/g' | od -vAn -tx1c
4c 6f cc 88 66 66 6c 65 72 20 4c c3 b6 66 66 6c
L o 314 210 f f l e r L 303 266 f f l
65 72 20 4c c3 b6 66 66 6c 65 72 0a
e r L 303 266 f f l e r \n
并且仅以 NFC 形式工作:
$ echo *ffler | uconv -x any-nfc | sed 's/\xd3\xa7/\xc3\xb6/g' | od -vAn -tx1c
4c c3 b6 66 66 6c 65 72 20 4c c3 b6 66 66 6c 65
L 303 266 f f l e r L 303 266 f f l e
72 20 4c c3 b6 66 66 6c 65 72 0a
r L 303 266 f f l e r \n
现在这三个名字一模一样。
以上内容是否澄清了您真正的担忧?
还接近吗?