imz*_*hev 8 ssh terminal character-encoding filenames altlinux
我正在通过 ssh 连接到远程系统,其中使用了不同的文件名编码(以及用户的语言环境)。这会导致一些问题。
在我开始讨论文件名问题之前,我想说,通过设置远程语言环境使其与本地语言环境相匹配,可以解决此类 ssh 会话的一些编码问题,即,
[imz@localhost ~]$ locale
LANG=ru_RU.UTF-8
LC_CTYPE="ru_RU.UTF-8"
LC_NUMERIC="ru_RU.UTF-8"
LC_TIME="ru_RU.UTF-8"
LC_COLLATE="ru_RU.UTF-8"
LC_MONETARY="ru_RU.UTF-8"
LC_MESSAGES="ru_RU.UTF-8"
LC_PAPER="ru_RU.UTF-8"
LC_NAME="ru_RU.UTF-8"
LC_ADDRESS="ru_RU.UTF-8"
LC_TELEPHONE="ru_RU.UTF-8"
LC_MEASUREMENT="ru_RU.UTF-8"
LC_IDENTIFICATION="ru_RU.UTF-8"
LC_ALL=
[imz@localhost ~]$ echo ??????
??????
[imz@localhost ~]$ echo ???
???
[imz@localhost ~]$ ssh -vv ivan@example.com
Last login: Fri Nov 25 13:44:56 2011 from NN.NN.NN.NN
[ivan@dell ~]$ locale
LANG=ru_RU.KOI8-R
LC_CTYPE="ru_RU.KOI8-R"
LC_NUMERIC="ru_RU.KOI8-R"
LC_TIME="ru_RU.KOI8-R"
LC_COLLATE="ru_RU.KOI8-R"
LC_MONETARY="ru_RU.KOI8-R"
LC_MESSAGES=POSIX
LC_PAPER="ru_RU.KOI8-R"
LC_NAME="ru_RU.KOI8-R"
LC_ADDRESS="ru_RU.KOI8-R"
LC_TELEPHONE="ru_RU.KOI8-R"
LC_MEASUREMENT="ru_RU.KOI8-R"
LC_IDENTIFICATION="ru_RU.KOI8-R"
LC_ALL=
[ivan@dell ~]$ echo ??????
??????
[ivan@dell ~]$ echo ???
????Ð
[ivan@dell ~]$ export LANG=ru_RU.UTF-8
[ivan@dell ~]$ echo ??????
??????
[ivan@dell ~]$ echo ???
???
[ivan@dell ~]$
Run Code Online (Sandbox Code Playgroud)
[ivan@dell ~]$ echo ?????? | fgrep -i ???
??????
[ivan@dell ~]$
Run Code Online (Sandbox Code Playgroud)
但这在以前是行不通的。
打印文件名的实用程序(您记得,这些文件名以不同的编码远程存储)不会逐字打印,但它们会用问号代替外来字符:
[ivan@dell ~]$ find ~mama/Desktop/ -iname '*.xls'
/home/mama/Desktop/????????? ????????.xls
/home/mama/Desktop/???????? ??? ???????????? (1).xls
/home/mama/Desktop/???????? ??? ???????????? (2).xls
/home/mama/Desktop/???????? ??? ???????????? (3).xls
/home/mama/Desktop/???????? ??? ????????????.xls
[ivan@dell ~]$ find ~mama/Desktop/ -iname '*.xls' -print
/home/mama/Desktop/????????? ????????.xls
/home/mama/Desktop/???????? ??? ???????????? (1).xls
/home/mama/Desktop/???????? ??? ???????????? (2).xls
/home/mama/Desktop/???????? ??? ???????????? (3).xls
/home/mama/Desktop/???????? ??? ????????????.xls
[ivan@dell ~]$
Run Code Online (Sandbox Code Playgroud)
同样的问题出现在ls
, 等等。但这可以通过将它们作为字符串传递给打印命令来轻松克服(不知道文件名和终端的不匹配编码的问题 - 或者出于任何原因,但它有效):
[ivan@dell ~]$ find ~mama/Desktop/ -iname '*.xls' -print0 | xargs -0 -n 1 echo
/home/mama/Desktop/Êðåäèòíûé ïîðòôåëü.xls
/home/mama/Desktop/ÀÄÐÅÑÀÒÛ äëÿ ïîçäðàâëåíèé (1).xls
/home/mama/Desktop/ÀÄÐÅÑÀÒÛ äëÿ ïîçäðàâëåíèé (2).xls
/home/mama/Desktop/ÀÄÐÅÑÀÒÛ äëÿ ïîçäðàâëåíèé (3).xls
/home/mama/Desktop/ÀÄÐÅÑÀÒÛ äëÿ ïîçäðàâëåíèé.xls
[ivan@dell ~]$
Run Code Online (Sandbox Code Playgroud)
此外,它们不可读的事实并不是很烦人,因为我总是可以| recode -f cp1251..utf-8
在命令的末尾附加一个。
基本问题是在终端中选择(用鼠标)文件名并粘贴它们不起作用:
[ivan@dell ~]$ diff '/home/mama/Desktop/ÀÄÐÅÑÀÒÛ äëÿ ïîçäðàâëåíèé (1).xls' '/home/mama/Desktop/ÀÄÐÅÑÀÒÛ äëÿ ïîçäðàâëåíèé (3).xls'
diff: /home/mama/Desktop/ÀÄÐÅÑÀÒÛ äëÿ ïîçäðàâëåíèé (1).xls: No such file or directory
diff: /home/mama/Desktop/ÀÄÐÅÑÀÒÛ äëÿ ïîçäðàâëåíèé (3).xls: No such file or directory
[ivan@dell ~]$
Run Code Online (Sandbox Code Playgroud)
我注意到输出中文件名的转义表示stat
,因此我能够选择并粘贴它($''
在bash 中):
[ivan@dell ~]$ diff '/home/mama/Desktop/\300\304\320\305\321\300\322\333 \344\353\377 \357\356\347\344\360\340\342\353\345\355\350\351 (1).xls' '/home/mama/Desktop/\300\304\320\305\321\300\322\333 \344\353\377 \357\356\347\344\360\340\342\353\345\355\350\351 (3).xls'
diff: /home/mama/Desktop/\300\304\320\305\321\300\322\333 \344\353\377 \357\356\347\344\360\340\342\353\345\355\350\351 (1).xls: No such file or directory
diff: /home/mama/Desktop/\300\304\320\305\321\300\322\333 \344\353\377 \357\356\347\344\360\340\342\353\345\355\350\351 (3).xls: No such file or directory
[ivan@dell ~]$ diff $'/home/mama/Desktop/\300\304\320\305\321\300\322\333 \344\353\377 \357\356\347\344\360\340\342\353\345\355\350\351 (1).xls' $'/home/mama/Desktop/\300\304\320\305\321\300\322\333 \344\353\377 \357\356\347\344\360\340\342\353\345\355\350\351 (3).xls'
Files /home/mama/Desktop/ÀÄÐÅÑÀÒÛ äëÿ ïîçäðàâëåíèé (1).xls and /home/mama/Desktop/ÀÄÐÅÑÀÒÛ äëÿ ïîçäðàâëåíèé (3).xls differ
[ivan@dell ~]$
Run Code Online (Sandbox Code Playgroud)
所以,问题是:
如何方便地使用不同编码的远程文件名(通过ssh)?
如果它们可读,并且可以选择和粘贴(并且我也可以从键盘输入,然后可以在bash 中通过 Tab 完成;为了方便我输入,它们当然必须是可读的),那就太好了。
我在工作urxvt在X.org上的Linux本地主机上,它的庆典上的Linux在远端。
在支持 UTF-8 的终端模拟器中,您可以使用该luit
命令在不同的区域设置中运行子 shell(或其他程序)。指示字符集的区域设置是LC_CTYPE
。
LC_CTYPE=ru_RU.KOI8-R luit ls # run one command
LC_CTYPE=ru_RU.KOI8-R luit # start a shell (type Ctrl+D or exit to return to the parent shell)
Run Code Online (Sandbox Code Playgroud)
如果您有不同编码的整个文件树,我建议(如果可能)通过convmvfs挂载它。
mkdir ~/net/ivan@example.com.KOI8-R ~/net/ivan@example.com.UTF-8
sshfs ivan@example.com: ~/net/ivan@example.com.KOI8-R
convmvfs -o srcdir=~/net/ivan@example.com.KOI8-R,icharset=KOI8-R,ocharset=UTF-8 ~/net/ivan@example.com.UTF-8
ls ~/net/ivan@example.com.UTF-8
Run Code Online (Sandbox Code Playgroud)
也许,人们可能会考虑使用一些复杂的终端模拟器,例如screen(在任一端)来翻译字符(或使用某些ssh翻译扩展名...),或者可以远程设置文件系统的convmvfs视图(使用文件名重新编码为本地编码),但有一个简单的解决方案:
只需在本地主机上创建一个专门用于与该远程主机一起工作的“环境”,并在该环境中工作(运行ssh等),即在远程文件名位于CP1251中的情况下,在X中启动一个新终端这适用于该编码:
$ LC_CTYPE=ru_RU.CP1251 xvt &
Run Code Online (Sandbox Code Playgroud)
并从中开展工作。(如果你比 X 更喜欢 Linux 控制台,也许你可以相应地设置一个虚拟 Linux 控制台,但关于设置 Linux 控制台的知识已经从我的脑海中消失了......)