为什么更改通过“ ssh -t”传输的二进制文件?

多坦科恩

我正在尝试通过SSH复制文件,但scp由于不知道我需要的确切文件名而无法使用尽管小型二进制文件和文本文件可以很好地传输,但是大型二进制文件会被更改。这是服务器上的文件:

remote$ ls -la
-rw-rw-r--  1 user user 244970907 Aug 24 11:11 foo.gz
remote$ md5sum foo.gz 
9b5a44dad9d129bab52cbc6d806e7fda foo.gz

这是我将其移至文件之后的文件:

local$ time ssh [email protected] -t 'cat /path/to/foo.gz' > latest.gz

real    1m52.098s
user    0m2.608s
sys     0m4.370s
local$ md5sum latest.gz
76fae9d6a4711bad1560092b539d034b  latest.gz

local$ ls -la
-rw-rw-r--  1 dotancohen dotancohen 245849912 Aug 24 18:26 latest.gz

请注意,下载的文件大于服务器上的文件但是,如果我对一个很小的文件执行相同的操作,那么一切都会按预期进行:

remote$ echo "Hello" | gzip -c > hello.txt.gz
remote$ md5sum hello.txt.gz
08bf5080733d46a47d339520176b9211  hello.txt.gz

local$ time ssh [email protected] -t 'cat /path/to/hello.txt.gz' > hi.txt.gz

真正的0m3.041s用户0m0.013s sys 0m0.005s

local$ md5sum hi.txt.gz
08bf5080733d46a47d339520176b9211  hi.txt.gz

在这种情况下,两个文件大小均为26字节。

为什么小文件可以很好地传输,而大文件却增加了一些字节?

斯蒂芬·查泽拉斯(Stephane Chazelas)

TL; DR

不要使用-t-t涉及远程主机上的伪终端,仅应用于从终端运行可视应用程序。

解释

换行符(也称为换行符或\n)是发送到终端时告诉终端将其光标向下移动的字符。

但是,当您seq 3在终端中运行时,即在其中seq写入1\n2\n3\n类似的内容/dev/pts/0,您不会看到:

1
 2
  3

1
2
3

这是为什么?

实际上,当seq 3(或ssh host seq 3就此而言)写入时1\n2\n3\n,终端会看到1\r\n2\r\n3\r\n即,换行已转换为回车(终端将光标移回屏幕左侧)并换行。

这是由终端设备驱动程序完成的。更确切地说,根据终端(或伪终端)设备的线路规范,驻留在内核中的软件模块。

您可以使用stty命令来控制该行规程的行为LF->的翻译用CRLF打开

stty onlcr

(通常默认情况下启用)。您可以使用以下方法将其关闭:

stty -onlcr

或者,您可以使用以下命令关闭所有输出处理:

stty -opost

如果执行该操作并运行seq 3,那么您将看到:

$ stty -onlcr; seq 3
1
 2
  3

如预期的那样。

现在,当您执行以下操作时:

seq 3 > some-file

seq不再写入终端设备,而是写入常规文件,无需进行翻译。所以some-file确实包含1\n2\n3\n仅在写入终端设备时才执行转换。并且仅用于显示。

同样,当您执行以下操作时:

ssh host seq 3

ssh正在写,1\n2\n3\n而不管ssh输出结果如何。

实际发生的是该seq 3命令在host其标准输出重定向到管道的情况下运行。ssh主机上服务器读取管道的另一端,并通过加密通道将其发送到ssh客户端,然后ssh客户端将其写入其stdout中(在您的情况下是伪终端设备),将LFs转换为此值以CRLF进行显示。

当标准输出不是终端时,许多交互式应用程序的行为会有所不同。例如,如果您运行:

ssh host vi

vi不喜欢它,不喜欢它的输出到管道。它认为它不是在与能够理解例如光标定位转义序列的设备通信。

因此ssh可以-t选择。使用该选项,主机上的ssh服务器将创建一个伪终端设备,并使stdout(以及stdin和stderr)成为vi什么vi写道,终端装置通过该远程伪终端线路规则并且由所读出的ssh服务器和发送过来的加密的信道的ssh客户机。除了使用管道代替之外,ssh服务器使用伪终端,与之前相同

另一个区别是在客户端,ssh客户端将终端设置为raw模式。这意味着在那里没有完成翻译(opost被禁用以及其他输入端行为)。例如,当您键入时,该字符将被发送到远程端Ctrl-C,而不是打断ssh^C字符,远程伪终端的线路规则将中断发送到远程命令。

当您这样做时:

ssh -t host seq 3

seq 3写入1\n2\n3\n其stdout,这是一个伪终端设备。由于onlcr,它会在主机1\r\n2\r\n3\r\n转换为加密通道并通过加密通道发送给您。在您这一边,没有翻译(已onlcr禁用),因此1\r\n2\r\n3\r\n未显示(由于该raw模式),并且已在终端仿真器的屏幕上正确显示。

现在,如果您这样做:

ssh -t host seq 3 > some-file

与上面没有区别。ssh会写同样的东西:1\r\n2\r\n3\r\n,但是这次变成了some-file

因此,基本上所有的LF输出seq都已转换CRLFsome-file

如果您这样做,则是相同的:

ssh -t host cat remote-file > local-file

所有LF字符(0x0a字节)都将转换为CRLF(0x0d 0x0a)。

这可能是文件损坏的原因。对于第二个较小的文件,恰好该文件不包含0x0a字节,因此没有损坏。

请注意,使用不同的tty设置可能会导致不同类型的损坏。与之相关的另一种潜在损坏类型-t是,您在host~/.bashrc~/.ssh/rc...)上的启动文件将内容写入其stderr,因为-t远程外壳程序的stdout和stderr最终被合并到ssh的stdout中(它们都进入了伪指令)。 -终端设备)。

您不希望遥控器cat输出到那里的终端设备。

你要:

ssh host cat remote-file > local-file

您可以这样做:

ssh -t host 'stty -opost; cat remote-file` > local-file

这将起作用(除了上面讨论的stderr损坏案例中的写法除外),但即使那样也将是次优的,因为您将在上运行不必要的伪终端层host


更有趣:

$ ssh localhost echo | od -tx1
0000000 0a
0000001

好的。

$ ssh -t localhost echo | od -tx1
0000000 0d 0a
0000002

LF 翻译成 CRLF

$ ssh -t localhost 'stty -opost; echo' | od -tx1
0000000 0a
0000001

再次确定。

$ ssh -t localhost 'stty olcuc; echo x'
X

这是终端线路部门可以完成的另一种输出后处理形式。

$ echo x | ssh -t localhost 'stty -opost; echo' | od -tx1
Pseudo-terminal will not be allocated because stdin is not a terminal.
stty: standard input: Inappropriate ioctl for device
0000000 0a
0000001

ssh当其自己的输入不是终端时,拒绝告诉服务器使用伪终端。您可以通过以下方式强制执行-tt

$ echo x | ssh -tt localhost 'stty -opost; echo' | od -tx1
0000000   x  \r  \n  \n
0000004

线规在输入方面做得更多。

在这里,echo既不读取其输入,也不要求其输出,x\r\n\n那么它是从哪里来的呢?这是echo远程伪终端(stty echo的本地地址所述ssh服务器被供给x\n它从客户端读取到远程伪终端的主侧。并且该行的规则将其回显(在stty opost运行之前,这就是为什么我们看到aCRLF和not的原因LF)。这与远程应用程序是否从stdin读取任何内容无关。

$ (sleep 1; printf '\03') | ssh -tt localhost 'trap "echo ouch" INT; sleep 2'
^Couch

0x3字符被回送为^C^C),因为stty echoctl和壳和睡眠接收SIGINT因为stty isig

因此,当:

ssh -t host cat remote-file > local-file

够糟糕的,但是

ssh -tt host 'cat > remote-file' < local-file

以另一种方式传输文件的情况要差得多。你会得到一些CR - > LF翻译,而且问题的所有特殊字符(^C^Z^D^?^S...),也是远程cat不会EOF看到,当年底local-file达到,只有当^D被后发送\r\n或其他^D喜欢做的时候cat > file在你的终端。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何通过ssh尾随二进制文件?

来自分类Dev

在SFTP中通过二进制模式传输文件

来自分类Dev

无法在Solaris系统上执行二进制文件-通过SSH

来自分类Dev

cat为什么更改二进制文件的内容?

来自分类Dev

通过libcurl以二进制格式传输的文件已损坏

来自分类Dev

通过发布请求传输django二进制文件数据

来自分类Dev

为什么“二进制文件”不在原始二进制文件中?

来自分类Dev

当通过 ssh 检索二进制文件时,是什么导致 \r's 被插入到 \n's 之前,我该如何规避它?

来自分类Dev

通过ssh将脚本和二进制数据传递到stdin

来自分类Dev

为什么git索引文件是二进制的?

来自分类Dev

为什么忽略二进制文件是最佳做法?

来自分类Dev

为什么函数定义的顺序会更改输出二进制文件?

来自分类Dev

为什么每次重建时go go二进制文件都会更改?

来自分类Dev

为什么函数定义的顺序会更改输出二进制文件?

来自分类Dev

C通过二进制文件生成头文件

来自分类Dev

是什么使grep认为文件是二进制文件?

来自分类Dev

通过RabbitMQ发送二进制文件

来自分类Dev

通过TCP / IP连接发送二进制文件

来自分类Dev

尝试通过Logstash传递二进制文件

来自分类Dev

通过串行终端发送二进制文件

来自分类Dev

通过RabbitMQ发送二进制文件

来自分类Dev

通过TCP / IP连接发送二进制文件

来自分类Dev

通过串行终端发送二进制文件

来自分类Dev

通过 systemctl 运行二进制文件

来自分类Dev

无法通过二进制文件使 Gdal 1.11.2 工作

来自分类Dev

通过 C++ 读取二进制文件的问题

来自分类Dev

通过 Flask 发送二进制文件列表

来自分类Dev

编译后更改二进制文件目录

来自分类Dev

更改localhost使用的PHP二进制文件

Related 相关文章

  1. 1

    如何通过ssh尾随二进制文件?

  2. 2

    在SFTP中通过二进制模式传输文件

  3. 3

    无法在Solaris系统上执行二进制文件-通过SSH

  4. 4

    cat为什么更改二进制文件的内容?

  5. 5

    通过libcurl以二进制格式传输的文件已损坏

  6. 6

    通过发布请求传输django二进制文件数据

  7. 7

    为什么“二进制文件”不在原始二进制文件中?

  8. 8

    当通过 ssh 检索二进制文件时,是什么导致 \r's 被插入到 \n's 之前,我该如何规避它?

  9. 9

    通过ssh将脚本和二进制数据传递到stdin

  10. 10

    为什么git索引文件是二进制的?

  11. 11

    为什么忽略二进制文件是最佳做法?

  12. 12

    为什么函数定义的顺序会更改输出二进制文件?

  13. 13

    为什么每次重建时go go二进制文件都会更改?

  14. 14

    为什么函数定义的顺序会更改输出二进制文件?

  15. 15

    C通过二进制文件生成头文件

  16. 16

    是什么使grep认为文件是二进制文件?

  17. 17

    通过RabbitMQ发送二进制文件

  18. 18

    通过TCP / IP连接发送二进制文件

  19. 19

    尝试通过Logstash传递二进制文件

  20. 20

    通过串行终端发送二进制文件

  21. 21

    通过RabbitMQ发送二进制文件

  22. 22

    通过TCP / IP连接发送二进制文件

  23. 23

    通过串行终端发送二进制文件

  24. 24

    通过 systemctl 运行二进制文件

  25. 25

    无法通过二进制文件使 Gdal 1.11.2 工作

  26. 26

    通过 C++ 读取二进制文件的问题

  27. 27

    通过 Flask 发送二进制文件列表

  28. 28

    编译后更改二进制文件目录

  29. 29

    更改localhost使用的PHP二进制文件

热门标签

归档