没有在ssh中分配terminal的好处是什么?

每隔一段时间我会做一些类似的事情

ssh user@host sudo thing 

我提醒说,ssh默认不会分配一个伪tty。 为什么不呢? 如果我使用ssh作为ssh -t会有什么好处?

主要的区别是交互的概念。 这与在脚本内部本地运行命令类似,而不是自己input。 不同之处在于,远程命令必须select默认,而非交互是最安全的。 (通常最诚实的)

STDIN

  • 如果分配了PTY,应用程序可以检测到这一点,并知道可以安全地提示用户input额外的input而不会破坏事物。 如果没有terminal在场,有许多程序会跳过提示用户input的步骤,这是一件好事。 否则会导致脚本不必要的挂起。
  • 您的input将在命令的持续时间内发送到远程服务器。 这包括控制序列。 虽然Ctrl-c中断通常会导致ssh命令中的循环立即中断,但您的控制序列将被发送到远程服务器。 这导致需要“锤击”击键以确保当控制离开 ssh命令时,但在下一个ssh命令开始之前到达击键。

我会告诫不要在无人参与的脚本中使用ssh -t ,比如cron。 要求远程命令以交互方式进行input的非交互式shell要求各种各样的麻烦。

您也可以在自己的shell脚本中testingterminal的存在。 使用更新版本的bashtestingSTDIN:

 # fd 0 is STDIN [ -t 0 ]; echo $? 

STDOUT

  • 当别名sshssh -t ,你可以期望在你的行结束时获得额外的回车。 它可能不是可见的,但它在那里; 它会显示为^M时,pipe道cat -e 。 然后,您必须花费额外的努力,确保这个控制代码不会被分配给您的variables,特别是如果您要将输出插入数据库。
  • 程序也有假设他们可以呈现对文件redirect不友好的输出的风险。 通常情况下,如果你要将STDOUTredirect到一个文件,程序会认识到你的STDOUT不是一个terminal,并且省略了任何颜色代码。 如果STDOUTredirect来自ssh客户端的输出,并且有与客户端的远程端相关的PTY,则远程程序不能做出这样的区分,并且在输出文件中将终止垃圾。 将输出redirect到远程连接的文件仍应按预期工作。

这是与前面相同的bashtesting,但对于STDOUT:

 # fd 1 is STDOUT [ -t 1 ]; echo $? 

尽pipe可以解决这些问题,但是你不可避免地要忘记围绕它们devise脚本。 我们所有人都在做某件事。 你的团队成员也可能不会意识到/记住这个别名已经存在,当他们编写使用别名的脚本时,这又会给你带来麻烦。

ssh -tssh -t就是一个很大的情况,在这种情况下你会违反最不让人意外的devise原则。 人们会遇到他们所不期望的问题,也不知道是什么原因造成的。

SSH转义字符和二进制文件的传输

其他答案中没有提到的一个优点是,在没有伪terminal的情况下运行时, 不支持 〜C等SSH 转义字符 。 这使程序可以安全地传输可能包含这些序列的二进制文件。

概念validation

使用伪terminal复制二进制文件:

 $ ssh -t anthony@remote_host 'cat /usr/bin/free' > ~/free Connection to remote_host closed. 

不使用伪terminal复制二进制文件:

 $ ssh anthony@remote_host 'cat /usr/bin/free' > ~/free2 

这两个文件是不一样的:

 $ diff ~/free* Binary files /home/anthony/free and /home/anthony/free2 differ 

用伪terminal拷贝的是损坏的:

 $ chmod +x ~/free* $ ./free Segmentation fault 

而另一个则不是:

 $ ./free2 total used free shared buffers cached Mem: 2065496 1980876 84620 0 48264 1502444 -/+ buffers/cache: 430168 1635328 Swap: 4128760 112 4128648 

通过SSH传输文件

这对于使用SSH进行数据传输的程序(如scprsync )尤为重要。 SCP协议如何工作的详细说明解释了SCP协议是如何由文本协议消息和二进制文件数据组成的混合体。


OpenSSH有助于保护你自己

值得注意的是,即使使用了-t标志,如果OpenSSH ssh客户端检测到它的stdinstream不是terminal,它将拒绝分配一个伪terminal:

 $ echo testing | ssh -t anthony@remote_host 'echo $TERM' Pseudo-terminal will not be allocated because stdin is not a terminal. dumb 

你仍然可以强制OpenSSH客户端用-tt分配一个伪terminal:

 $ echo testing | ssh -tt anthony@remote_host 'echo $TERM' xterm 

在任何一种情况下,它(明智地)不关心stdoutstderr是否被redirect:

 $ ssh -t anthony@remote_host 'echo $TERM' >| ssh_output Connection to remote_host closed. 

在远程主机上,我们必须使用这个设置:

 /etc/sudoers ... Defaults requiretty 

没有sudo

 $ ssh -T user@host echo -e 'foo\\nbar' | cat -e foo$ bar$ 

和sudo

 $ ssh -T user@host sudo echo -e 'foo\\nbar' | cat -e sudo: sorry, you must have a tty to run sudo 

随着sudo我们得到额外的回车

 $ ssh -t user@host sudo echo -e 'foo\\nbar' | cat -e foo^M$ bar^M$ Connection to localhost closed. 

解决scheme是禁用翻译换行符回车换行stty -onlcr

 $ ssh -t user@host stty -onlcr\; sudo echo -e 'foo\\nbar' | cat -e foo$ bar$ Connection to localhost closed. 

man ssh

  -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, eg when implementing menu services. Multiple -t options force tty allocation, even if ssh has no local tty. 

这可以让你得到一个“壳”到远程服务器。 对于授予shell访问权限但允许使用SSH的服务器(例如,Github是SFTP访问的已知示例),使用此标志将导致服务器拒绝您的连接。

shell也有你所有的环境variables(如$PATH ),所以执行脚本通常需要一个tty才能工作。

考虑向后兼容性。

ssh的两个主要模式是交互式的,用tty和指定的命令(不带tty)进行交互式login,因为它们分别是rloginrsh的确切function。 ssh需要提供rlogin / rsh特性的超集才能成功取代。

所以默认是在ssh出生前决定的。 像“我想指定一个命令得到一个tty”的组合必须被新的选项访问。 很高兴至less我们现在这个select,不像我们使用rsh 。 我们没有交换任何有用的function来获得encryption连接。 我们有奖金function!