在OS X中文件名的不同UTF8编码

22

我有一个小的shell脚本在.x中。

$ cat .x
u="Böhmáí"
touch "$u"
ls > .list
echo "$u" >.text

cat .list .text
diff .list .text
od -bc .list
od -bc .text

当我运行这个脚本 sh -x .x(-x只是用来显示命令)时

$ sh -x .x
+ u=Böhmáí
+ touch Böhmáí
+ ls
+ echo Böhmáí
+ cat .list .text
Böhmáí
Böhmáí
+ diff .list .text
1c1
< Böhmáí
---
> Böhmáí
+ od -bc .list
0000000   102 157 314 210 150 155 141 314 201 151 314 201 012            
           B   o   ̈    **   h   m   a   ́    **   i   ́    **  \n            
0000015
+ od -bc .text
0000000   102 303 266 150 155 303 241 303 255 012                        
           B   ö  **   h   m   á  **   í  **  \n                        
0000012

在文件名与文件内容中,相同的字符串Böhmáí被编码为不同的字节。在终端(utf8编码)中,这个字符串在这两种情况下看起来相同

兔子在哪里?


类似问题:https://dev59.com/NGfWa4cB1Zd3GeqPj8Dw - SimonSimCity
1个回答

45
(This is mostly stolen from a previous answer of mine...)
Unicode允许一些带重音的字符以几种不同的方式表示:作为代表带重音字符的“代码点”,或者作为代表未带重音版本的字符的一系列代码点,后跟重音符号。例如,“ä”可以被表示为U+00E4(UTF-8 0xc3a4,带分音符的小写拉丁字母1)或U+0061 U+0308(UTF-8 0x61cc88,拉丁小写字母a + 连接用分音符)。
OS X的HFS+文件系统要求所有文件名都以其完全分解形式的UTF-8表示存储。在HFS+文件名中,“ä”必须编码为0x61cc88,“ö”必须编码为0x6fcc88。
因此,在这里发生的情况是,您的shell脚本包含以预组合形式的“Böhmáí”,因此它以该方式存储在变量a中,并以该方式存储在.text文件中。但是,当您创建具有该名称的文件(使用touch)时,文件系统将其转换为实际文件名的分解形式。并且当您ls它时,它显示文件系统具有的形式:分解形式。

3
HFS+ 实际上使用了 NFD(分解的规范化格式)的一种变体,其中某些字符范围被预组合,因此文件名并没有完全分解。请参见 VFS 中的文本编码 - Lri
谢谢,非常有帮助。这个HFS+文件系统要求使用NFD是否也会影响其他文件系统,例如,在Mac上挂载的FAT32 SD卡? - LarsH
1
@LarsH:我刚刚在OS X(v10.11.3)上测试了在FAT32上创建文件,它确实转换为NFD形式。我不知道其他平台是否会这样做,也不知道以其他形式命名的文件将如何显示在OS X上。 - Gordon Davisson
感谢您测试并报告结果。在我发布上面的评论后,我发现我在FAT32微型SD卡上拥有的目录名称以预组合(NFC,我认为)形式存在,与MacOS X要求的不同。微型SD卡上的文件和目录是通过将它们通过USB电缆复制到Android设备上创建的,可以通过Finder中的挂载卷或通过Android文件传输进行操作 - 我不记得哪个了。 - LarsH
我在我的MacOS Catalina版本10.15.6上无法重现这个问题。touch和连续的ls都有NFC字符串。好的,我使用了复制和粘贴,但通常情况下,复制和粘贴不会进行规范化,而uni identify是可靠的。 - Helmut Wollmersdorfer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接