使用终端与使用 shell 脚本的不同编码/Unicode 解释

And*_*5_5 3 terminal character-encoding perl shell-script unicode

我正在编写键盘映射脚本(将按键从一种语言键盘布局映射到另一种语言键盘布局)。经过大量努力让一切正常工作后,我发现不同的字符在所有程序(perl、python)中的处理方式不同。然后我在终端(kitty、gnome-terminal \xe2\x80\x94 没关系)中运行一个简单的测试脚本(现已简化):

\n
python -c \'import sys;print(len(sys.argv[1]))\' \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88\n
Run Code Online (Sandbox Code Playgroud)\n

并得到了预期的结果:

\n
3\n
Run Code Online (Sandbox Code Playgroud)\n

但是如果我在 sh/bash (unix&utf-8) 文件中运行它:

\n
3\n
Run Code Online (Sandbox Code Playgroud)\n

我得到(./test.sh):

\n
9\n
Run Code Online (Sandbox Code Playgroud)\n

这就是所有这些编码/解码/升级/降级 UTF-8 内容在 Perl 中不起作用的原因(如果我从终端手动运行该命令,它可能会在没有所有这些附加编码功能的情况下工作)。

\n

现在我有一个问题:为什么完全相同的命令根据执行环境(终端模拟器与 shell 脚本)给出不同的结果?我怎样才能解决这个问题?

\n

更新

\n

我忘记了我的:

\n
#!/usr/bin/env bash\n# or\n#!/bin/sh\npython -c \'import sys;print(len(sys.argv[1]))\' \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88\n
Run Code Online (Sandbox Code Playgroud)\n

因此,对于 Python,python3显式运行使得在这两种情况下一切都一样。但另一方面,对于 Perl:

\n
9\n
Run Code Online (Sandbox Code Playgroud)\n

其工作原理相同,但在两种情况下都会输出9. Perl 没有不同的版本,我的版本是 5.30.0(两种情况下打印的版本完全相同)。我是否必须在 Perl 本身中添加一些代码才能使其像 Python3 一样工作(1 个 Unicode 字符的长度是 1 而不是 1-3 个字节)?

\n

ter*_*don 5

这不是关于 shell 而是关于python. 我可以通过使用 python3 然后使用 python2 显式运行相同的命令来重现此内容:

\n
$ python3 -c 'import sys;print(len(sys.argv[1]))' \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88\n3\n$ python2 -c 'import sys;print(len(sys.argv[1]))' \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88\n9\n
Run Code Online (Sandbox Code Playgroud)\n

由于您没有使用特定python可执行文件的完整路径,因此您的终端和脚本都将仅采用python它们在 .txt 中列出的目录中找到的第一个路径PATH。就您而言,非交互式 shell(运行脚本的 shell)中的 与交互式 shell(终端中)中的PATH不同,在前者中,显然指向 Python2 可执行文件。PATHpython

\n

python3我不知道你为什么有这个,我需要更多地了解你的设置和你正在使用的操作系统,但一个简单的解决方案,假设你在提供这个的系统上,是调用脚本的python

\n
python3 -c 'import sys;print(len(sys.argv[1]))' \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88\n
Run Code Online (Sandbox Code Playgroud)\n

或者,使用完整路径(参见type -a python):

\n
/usr/bin/python -c 'import sys;print(len(sys.argv[1]))' \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88\n
Run Code Online (Sandbox Code Playgroud)\n

这样您的结果将始终保持一致。

\n

  • @Andrew15_5 我可以保证你错过了一些东西,因为 i) Perl 实际上非常擅长处理 utf-8 和 ii) 处理 utf-8 非常复杂,所以我们都会错过一些东西,除非我们是真正的专家。也就是说,在这种情况下,一个简单的 `-CA` (它告诉 `perl` 它的 `@ARGV` 数组包含 UTF-8 文本)就足够了: `perl -CA -le 'print length($ARGV[0] )' テsuto`。 (2认同)