我最近切换到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中的任何文件
答案 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”,并会找到它;但是té
的制表符完成由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
中有一些来源;这创造了一系列重音'目录,每个目录包含一个重音文件。命令行工具没有问题。
这是我只能用图像演示的地方,我想:
这应该显示Finder查看文件夹naïve.c
中的文件naïve
。我能够在Finder中单击该文件并运行XCode:
首先,尝试将您的区域设置设置为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
将其删除。这个名字不是我所期待的。无法创建该文件。