“-bash:警告:setlocale:LC_ALL:无法更改区域设置(en_US.UTF-8)”

“-bash:警告:setlocale:LC_ALL:无法更改区域设置(en_US.UTF-8)”

运行全新的 Ubuntu 16.04 和 Debian 8 服务器。尝试通过 ssh 连接并获得以下奇怪的终端输出。我指的是其中带有数字的矩形。

语言设置的问题是我自己在尝试解决刚才提到的问题时引入的,因为我认为是一些编码问题造成的。经过 3 个小时的调试,我需要你的帮助!

也许只是缺少一个图书馆?很难找到这样的图形问题......

在此输入图像描述

local@local:~$ ssh dummy@server

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Jul  9 17:22:43 2016 from x590c3909.dyn.telefonica.de
-bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8)
-bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8)
-bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8)
]1337;RemoteHost=dummy@server]1337;CurrentDir=/home/patrick]1337;ShellIntegrationVersion=2;shell=bash]133;C;]133;D;0]1337;RemoteHost=dummy@server]1337;CurrentDir=/home/patrick]133;Adummy@server:~$ ]133;B

回显 $PS1 输出:

echo $PS1
]133;C;\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\u@\h:\w\$

回显 $TERM 输出:

echo $TERM
]133;C;xterm

编辑:“区域设置”-警告由这个答案

答案1

你的终端正在做什么

“[其中]包含数字的矩形”是终端仿真器向您显示终端控制序列的方式,因为它无法识别该序列。具体来说:

  • 有一个 ECMA-48 控制字符(在 C1 组中,用于技术)名为操作系统命令,缩写为OSC。它的 Unicode 值是 U+009D。
  • ECMA-48 定义了一种机制,其中 C1 组中的字符需要完全干净的 8 位通信路径才能传输,可以通过仅使用值小于 U+0080 (128) 的字符的转义序列来表示。这些7 位别名允许在非 8 位干净的传输路径上使用 C1 控制字符。具有讽刺意味的是,几十年来,世界基本上都是 8 位干净的。

    您很可能知道这些非常常见的 7 位别名之一:ESC[而不是 CSI 控制字符 (U+009B)。 OSC 控制字符有 ESC]作为 7 位别名。

  • SSH 连接远端的某些东西期望您的终端理解以 OSC 开头的控制序列。它使用 7 位别名传输它们。
  • 您的终端未完全实现 ECMA-48。它看到 ESC]并只是将其视为 ESC 字符后跟一个]字符。这就是它打印的内容。
  • 但它没有 ESC 字符的字形。因此,它又回到了传统的技巧,将没有字形的字符显示为一个盒子,其中包含 Unicode 代码点(最低 16 位)的十六进制值。如果仔细观察,您会在框中看到数字00和U+001B,这是 ESC 字符的代码点。1B
  • 它也没有正确处理为 ESC 打印的“间距”,即它在屏幕上占用的空间,这实际上是字符宽度。因此,打印盒子后,它不会提前输出位置足够的。然后它会打印]盒子右半部分的顶部,如您所见。

为什么被告知要这样做

一些终端仿真器将 OSC 识别为控制字符序列引入器。甚至还有一个标准形式。 ECMA-48 § 5.6 定义了以 OSC 开头并以 ST 终止的“控制字符串”(U+009C,字符串终止符)。什么是控制字符串是特定于终端类型的。例如:您将从 xterm 的 doco 中看到,它实现了此类控制字符串,用于设置字体和窗口标题。

但是,那形式这种情况下的控制序列不是 xterm 的控制序列。相反,它是

␛]1337;当前目录=/home/帕特里克␇

这是 iTerm2 可以理解的 OSC 控制序列的形式。 iTerm2 定义了 OSC 引入的一组控制序列,这些序列明显非标准且与 iTerm2 不同。它们不遵守 ECMA-48 控制字符串规范,而是使用 BEL (U+0007) 终止控制字符串,而不是按照标准规定使用 ST。严格来说,这是一个控制字符串从未被终止,因为控制字符串的内容中允许使用除 SOS 和 ST 之外的任何字符;并且是一种使用一致的终端仿真器有效地停止显示的方法,因为终端只是将所有进一步的输出作为控制字符串累积。

(Linux 内核中内置的终端仿真器也没有实现标准 OSC 控制字符串。xterm doco 指出,它具有支持使用不符合要求的 Linux 内核终端仿真器或 iTerm2 表单的损坏应用程序的能力。形式这里肯定是 iTerm2 的,而不是 Linux 内核终端模拟器的。)

当您从 Macintosh 使用 iTerm2 时,SSH 连接另一端的任何内容都会悄悄地将 iTerm2 控制序列发送到您的终端仿真器,告诉它诸如您的 shell 是什么、您的工作目录是什么、您是谁、何时执行等信息。当您开始执行命令时,您可以在 shell 提示符下开始编辑,等等。

在远程系统上,您有硬连线终端类型。您已经让它在您始终使用 iTerm2 与它对话的假设下运行。但你是现在使用 Ubuntu 上运行的 Terminator 与它对话,不同的终端模拟器有一个不同的控制序列集。

事实上,输出甚至告诉您:

␛]1337;ShellIntegrationVersion=2;shell=bash␇

您已在远程系统上为 Bourne Again shell 安装了 iTerm2“Shell 集成”。看看它,它在检查 iTerm2 是否确实是它正在对话的终端方面非常糟糕。

所以禁用/卸载它。

进一步阅读

  • 编码字符集的控制函数。 ECMA-48。 ECMA 国际。
  • console_codes。 Linux 手册页。 § 4.2015。
  • 马修·弗里曼、乔治·纳赫曼和詹姆斯·A·罗森。 专有转义码。 iTerm2 文档。
  • 马修·弗里曼、乔治·纳赫曼和詹姆斯·A·罗森。 外壳集成。 iTerm2 文档。

答案2

尝试ssh使用不同的前缀命令LC_ALL,例如

LC_ALL=C ssh dummy@server

相关内容