如果我运行:
scp [email protected]:/home/me/cömmön_file.jpg /home/me/
从我的远程服务器我得到:
scp:/home/me/cömmön_file.jpg:没有这样的文件或目录
如果我用通配符交换 utf8 字符,它将起作用:
scp [email protected]:/home/me/c?mm?n_file.jpg /home/me/
和/或
scp [email protected]:/home/me/c*mm*n_file.jpg /home/me/
如果我在远程计算机上使用 AWS CLI,该行为也会复制。
在我的远程计算机上运行具有显式名称的其他命令可以按照我的预期运行。
例如
ls -lha /home/me/cömmön_file.jpg
-rw-r--r--。 1 我我 1.1M Jan 15 21:58 /home/me/cömmön_file.jpg
我也可以使用 重命名文件mv
。
是传输文件的问题,还是托管该文件的计算机中的某些底层问题?
导致当前问题的 UTF8 字符是https://www.compart.com/en/unicode/U+0308但我怀疑其他角色也会重现这个问题。如果我尝试将文件从重命名ö
为https://www.compart.com/en/unicode/U+00F6我的机器告诉我文件是相同的。
mv: '/home/me/cömmön_file.jpg' 和 '/home/me/cömmön_file.jpg' 是同一个文件
托管该文件的服务器是:
NAME="CentOS Linux"
VERSION="7 (Core)"
它locale
是:
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
请求该文件的服务器是:
NAME="Amazon Linux"
VERSION="2"
它locale
是:
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
答案1
快速解决方案:不要在键盘上使用重音字母,而是使用制表符完成(并设置 SSH 密钥,以便制表符也可以通过网络使用scp
,rsync
等等)或回退到通配符,因为你经验是正常的预期行为。
这不起作用,因为您没有输入相同的文件名。
看起来很疯狂?这对你来说就是 UTF-8。
更疯狂的是:我可以用我的神奇的远程读心术精神力量告诉你你有一个苹果电脑。
更严重的是:这是您在提问时忘记提供的关键信息,但您在输入问题本身时不小心泄露了。
复制粘贴上面的答案时:
# echo "scp [email protected]:/home/me/cömmön_file.jpg" | hexdump -C
00000000 73 63 70 20 6d 65 40 65 78 61 6d 70 6c 65 2e 63 |scp [email protected]|
00000010 6f 6d 3a 2f 68 6f 6d 65 2f 6d 65 2f 63 6f cc 88 |om:/home/me/co..|
00000020 6d 6d 6f cc 88 6e 5f 66 69 6c 65 2e 6a 70 67 20 |mmo..n_file.jpg |
00000030 2f 68 6f 6d 65 2f 6d 65 2f 0a |/home/me/.|
0000003a
请密切注意字母“ö”的编码方式:6f cc 88
。一个字母“o”后跟一个额外的 UTF-8 代码点。 (事实上,在我的终端上它甚至不显示为“ö”而是显示为“o”)
当我(=Linux 用户)输入:
echo /home/me/cömmön_file.jpg | hexdump -C
00000000 2f 68 6f 6d 65 2f 6d 65 2f 63 c3 b6 6d 6d c3 b6 |/home/me/c..mm..|
00000010 6e 5f 66 69 6c 65 2e 6a 70 67 0a |n_file.jpg.|
0000001b
再次仔细观察“ö”符号:c3 b6
,这是一个完全不同的 UTF-8 代码点,并且没有额外的 ASCII 字符。
超简短的解释:UTF-8 标准化(组合与分解)。
更长的解释:
在 Unicode 中,有多种方法可以对类似“ö”的内容进行编码。
- 第一种方法是组成的字符:有一个代码点是从 Latin-1 (ISO/IEC 8859-1:1998) 代码点继承的“ö”,Unicode 代码点 U+00f6(在 UTF-8 中编码为 c3 b6)
- 第二种方法是分解的字符:首先输出 ASCII o,然后附加一个特殊代码点这意味着'请在前面的字母中添加变音符号', Unicode 代码点 U+0308(在 UTF-8 中编码为 cc 88)
正是这种组合可以使您能够完成所有̫cra̎zyshit̫ke̬̓ke̬̓king̬̓king̬̓KITHIPAIL, ̌m̳͌̽m̳͌̽a̪ͥd̺͑n͕͌̐e̿͊s͇s̘͓͊。
哼。
地球上的其他地方尽可能使用组合字符(因为它更紧凑,也因为它使用与 Latin-1 兼容的 Unicode 范围,简化了向后兼容性),并且只对没有其组合字符的事物使用组合字符。自己的代码点(主要是不太常见的语言)。
苹果显然生活在另一个星球上,他们决定始终尝试使用角色(因为他们崇拜黑暗的Za͓̙̘͌l̦̖͉̃ͦ͆͊ͧ̀g͖̭̼̗͉̦̬̍̀̌ͬ̓ͥ҉o̧͉̗̱̥̣̯͍̗̲̩ͪ͋̾͑̈́ͦ̐̓͘͡?)。
键入看起来像“ö”的键盘字母根本不会生成相同的二进制序列,具体取决于您键入该键的计算机。
然后,另一件事开始发挥作用:大多数 Unix 倾向于使用对大小写敏感且对 Unicode 编码(支持 UTF-8)敏感的文件系统(如 Linux 的 EXT4)。他们试图保留文本是否是撰写的。因此,6f cc 88
即使c3 b6
它们编码相同的最终结果“ö”,它们也会区分 UTF-8 二进制序列。 (以同样的方式区分“A”和“a”,即使它们是相同的拉丁字母)。所以你的键盘产生的“ö”和服务器上的“ö”不一样。
碰巧堆栈交换只是存储您按原样输入的任何 Unicode 编码,从而导致神秘的答案HTML 正则表达式解析器那些。 (因此,您的 Mac 通过记录“ö”的特定字节序列背叛了自己)。