带有特殊字符的Mac OSX终端文件夹名称

时间:2013-11-19 07:15:08

标签: macos shell encoding terminal

我最近切换到MAC OSX,在终端中创建包含特殊字符的目录时遇到了问题。

基本上会发生这样的事情:

  • 当我在té$t中创建目录Finder并复制文件时,我可以在终端和Finder中访问它
  • 当我在终端创建相同的目录té$ t并在其中放置一个文件时我可以在终端访问它,在Finder中我收到一个错误,指出找不到该文件。当我在终端重命名没有特殊字符的目录时,我可以在Finder中访问该文件。

    :> locale
    LANG=
    LC_COLLATE="C"
    LC_CTYPE="UTF-8"
    LC_MESSAGES="C"
    LC_MONETARY="C"
    LC_NUMERIC="C"
    LC_TIME="C"
    LC_ALL=
    

这必须是某种编码方式,对吗?

更新:

忘记$但只使用é代替(或任何其他áìç等等)。该文件夹已创建,只有当我在终端中创建时,我无法访问Finder中的任何文件

2 个答案:

答案 0 :(得分:4)

在unicode中,像é这样的重音字符通常可以用两种不同的方式表示:“预合成”作为表示重音字母的单个代码点,或“分解”为表示非重音字母后跟合并的一系列代码点重音(甚至不止一个......)。在“é”的情况下,其预先组合的形式将是U + 00e9 = UTF-8 0xc3a9 =“具有急性重音的拉丁小写字母e”,并且其分解形式将是U + 0065 U + 0301 = UTF-8 0x65cc81 = “拉丁文小写字母e”+“结合尖锐的口音”。

当您在终端中键入文件名时,您将以预先组合的形式键入它;但是Mac OS Extended文件系统以分解形式存储文件名(这里有一些不相关的例外)。当您指定包含预先组合字符的文件名时,文件系统将分解它们以进行存储。最终结果:当您稍后尝试使用该文件时,您尝试使用与文件的实际名称等效但不相同的名称来访问它。根据您访问它的具体方式,可能会或可能不会正确处理等效项,因此可能会找到或不会找到该文件。

通常,文件系统会像这样处理等价,但shell和其他程序不知道文件系统编码的细节,因此会出错。因此,如果shell / other程序只是将名称传递给文件系统代码,它就可以工作,但如果shell / other程序试图弄清楚文件是否存在,那么它就会失败。例如,touch "tést"; [ -e "tést" ]使用文件系统来查明是否存在“tést”,并会找到它;但是的制表符完成由shell处理,并且将失败。请参阅this apple.se question

答案 1 :(得分:1)

我无法在我的Mac上重现您的问题,但我没有按照您的方式处理我的语言环境。

终端

$ mkdir weird
$ cd weird
$ mkdir naïve résumé touché
$ for d in *; do cp ../q7.c $d/$d.c; done
$ ls -l *
naïve:
total 8
-rw-r-----  1 jleffler  staff  990 Nov 19 07:30 naïve.c

résumé:
total 8
-rw-r-----  1 jleffler  staff  990 Nov 19 07:30 résumé.c

touché:
total 8
-rw-r-----  1 jleffler  staff  990 Nov 19 07:30 touché.c
$ locale
LANG="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_CTYPE="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_ALL=
$ 

我碰巧在文件q7.c中有一些来源;这创造了一系列重音'目录,每个目录包含一个重音文件。命令行工具没有问题。

查找

这是我只能用图像演示的地方,我想:

enter image description here

这应该显示Finder查看文件夹naïve.c中的文件naïve。我能够在Finder中单击该文件并运行XCode:

enter image description here

建议

首先,尝试将您的区域设置设置为en_US.UTF-8,看看是否有任何区别。

如果,确实如此,那么我假设您使用Latin 1创建文件名,但Finder使用UTF-8运行。那么问题是您的文件名不是有效的UTF-8文件名。这可能会阻止Finder工作。

这是一个试图滥用系统的程序:

#include <sys/stat.h>
#include <stdio.h>

int main(void)
{
    char name[] = "\xC0\xC1\xC2\xC3\xC4\xC5\xC6";
    char file[] = "weird.c";

    /*
    C0 U+00C0 LATIN CAPITAL LETTER A WITH GRAVE
    C1 U+00C1 LATIN CAPITAL LETTER A WITH ACUTE
    C2 U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX
    C3 U+00C3 LATIN CAPITAL LETTER A WITH TILDE
    C4 U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS
    C5 U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE
    C6 U+00C6 LATIN CAPITAL LETTER AE
    */

    if (mkdir(name, 0755) != 0)
    {
        fprintf(stderr, "mkdir(%s) failed\n", name);
        return(1);
    }
    char buffer[32];
    snprintf(buffer, sizeof(buffer), "%s/%s.c", name, name);
    FILE *ofp = fopen(name, "w");
    if (ofp == 0)
    {
        fprintf(stderr, "fopen(%s) failed\n", buffer);
        return(1);
    }
    FILE *ifp = fopen(file, "r");
    if (ifp == 0)
    {
        fprintf(stderr, "fopen(%s) failed\n", file);
        return(1);
    }
    size_t nbytes;

    while ((nbytes = fread(buffer, 1, sizeof(buffer), ifp)) != 0)
        fwrite(buffer, 1, nbytes, ofp);
    fclose(ifp);
    fclose(ofp);
    return 0;
}

正如您可能知道的那样,字节0xC0和0xC1永远不会出现在格式良好的UTF-8中。其他字节是2字节UTF-8字符的合法起始字节,但后面的字节应始终在0x80..0xAF范围内。显然,这些名称并不是格式良好的UTF-8。

Osiris JL: make weird
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror weird.c -o weird  
Osiris JL: ls -l
total 40
-rw-r-----  1 jleffler  staff  1629 Nov 19 07:54 makefile
drwxr-----  4 jleffler  staff   136 Nov 19 07:36 naïve
drwxr-----  4 jleffler  staff   136 Nov 19 07:36 résumé
drwxr-----  4 jleffler  staff   136 Nov 19 07:36 touché
-rwxr-----  1 jleffler  staff  9068 Nov 19 08:00 weird
-rw-r-----  1 jleffler  staff  1142 Nov 19 07:59 weird.c
drwxr-----  3 jleffler  staff   102 Nov 19 08:00 weird.dSYM
Osiris JL: ./weird
fopen(???????/???????.c) failed
Osiris JL: ls -l
total 40
drwxr-----  2 jleffler  staff    68 Nov 19 08:00 %C0%C1%C2%C3%C4%C5%C6
-rw-r-----  1 jleffler  staff  1629 Nov 19 07:54 makefile
drwxr-----  4 jleffler  staff   136 Nov 19 07:36 naïve
drwxr-----  4 jleffler  staff   136 Nov 19 07:36 résumé
drwxr-----  4 jleffler  staff   136 Nov 19 07:36 touché
-rwxr-----  1 jleffler  staff  9068 Nov 19 08:00 weird
-rw-r-----  1 jleffler  staff  1142 Nov 19 07:59 weird.c
drwxr-----  3 jleffler  staff   102 Nov 19 08:00 weird.dSYM
Osiris JL:  rmdir *C6
Osiris JL: ./weird 2>&1 | odx
0x0000: 66 6F 70 65 6E 28 C0 C1 C2 C3 C4 C5 C6 2F C0 C1   fopen(......./..
0x0010: C2 C3 C4 C5 C6 2E 63 29 20 66 61 69 6C 65 64 0A   ......c) failed.
0x0020:
Osiris JL: 

所以,我能够以时尚的方式创建目录,但我可以使用rmdir *C6将其删除。这个名字不是我所期待的。无法创建该文件。