我曾经ssh
使用以下方法解压远程文件:
ssh host "cat file.tgz" | tar xf -
这工作得很好。但是我注意到在使用强制命令时,pty 分配会更改命令的输出:
ssh host -T "cat file.tgz" >first_file
ssh host -t "cat file.tgz" >second_file
这里第一个文件很好,但第二个文件已损坏。
为什么 pty 的分配会改变输出?
答案1
它有助于阅读ssh
手册页:
-T Disable pseudo-tty allocation.
-t Force pseudo-tty allocation. This can be used to execute arbi‐
trary screen-based programs on a remote machine, which can be
very useful, e.g. when implementing menu services. Multiple -t
options force tty allocation, even if ssh has no local tty.
当你告诉它分配A伪tty,远程端的任何进程都可以看到该连接是一个“真实”终端,并且由于该连接是交互式的,因此将发送附加消息。在 shell 初始化中,它还可以设置终端模式,您可以使用 进行检查stty -a
。终端模式用于翻译在键盘输入和主机之间,以及从主机发送到终端的文本之间:
- 没有初始化时,连接不是终端,并且不进行任何转换。
- 和初始化时,终端会将换行符 (
\n
) 转换为回车换行符 (0x0d、0x0a)。它还将(对于大多数用户)将制表符转换为空格。
所描述的效果是针对翻译。没有那个,你的交互的会话将“阶梯”穿过屏幕并且无法使用。
您的 shell 还可能打印附加信息,但对于单个命令,建议@kba 具有误导性,因为 shell 通常不会发送提示,以及上述的 ssh 控制~C
适用于输入而不是输出。
当运行到终端时,ssh 也会在关闭连接时打印一条消息。但这被写入标准错误。
答案2
为什么 pty 的分配会改变输出?
因为远程端(具有分配的终端)将为您的本地终端“注入”控制字符(基本上是C0和C1控制代码)。由于您的本地端不是终端,而是文件,因此它只是将它们转储到该文件中。
SSH 正在尽力猜测您想要什么(如果 stdin 不是 TTY,那么它不会分配远程 TTY,除非您添加-tt
开关)。该选项的存在是有原因的,如果您想要二进制传输,您不希望终端弄乱您的文件。
您只需传输小文件然后十六进制转储即可看到此行为:
$ ssh -t host "cat test" > /tmp/test.t
$ ssh host "cat test" > /tmp/test
$ hexdump -C /tmp/test
00000000 0a 2a 20 46 72 69 20 46 65 62 20 31 32 20 32 30 |.* Fri Feb 12 20|
00000030 6d 3e 20 33 2e 34 2e 31 2d 31 0a 2d 20 4e 65 77 |m> 3.4.1-1.- New|
$ hexdump -C /tmp/test.t
00000000 0d 0a 2a 20 46 72 69 20 46 65 62 20 31 32 20 32 |..* Fri Feb 12 2|
00000030 6f 6d 3e 20 33 2e 34 2e 31 2d 31 0d 0a 2d 20 4e |om> 3.4.1-1..- N|
对我来说,区别仅在于0d 0a
每个新行之前的两个字节,但可能还有更多(linux 行 Newline 仅是\n
,但终端同时获取两者\r\n
)。