在ssh中不分配终端有什么好处?


66

偶尔我会做类似的事情

ssh user@host sudo thing

并提醒我ssh默认情况下不分配伪tty。为什么不呢?如果我使用别名ssh,将会失去什么好处ssh -t


1
>提醒我ssh没有分配psuedo-tty会发生什么情况?它将丰富问题以了解问题所在。
航空

5
@Air我没有尝试解决的问题。我试图理解如何实现ssh。这个问题很明确,Andrew B的回答很好地解决了这个问题。答案可以这样概括:ssh -t始终运行很糟糕,因为它可能导致某些命令以奇怪的方式中断。而运行不需要PTY的命令将导致产生清晰的错误消息,提示您需要终端。
Chas。欧文斯(Owens)2014年

Answers:


73

主要区别在于交互性的概念。这类似于在脚本内部本地运行命令,而不是自己键入命令。区别在于,远程命令必须选择默认值,并且非交互式最安全。(通常最诚实)

标准输入

  • 如果分配了PTY,则应用程序可以检测到这一点,并且知道可以安全提示用户输入其他输入而不会造成任何麻烦。如果没有终端,有很多程序将跳过提示用户输入的步骤,这是一件好事。否则会导致脚本不必要地挂起。
  • 在命令执行期间,您的输入将被发送到远程服务器。这包括控制序列。虽然Ctrl-c中断通常会导致ssh命令上的循环立即中断,但是您的控制序列将被发送到远程服务器。这导致需要“敲击”击键以确保它在控制离开 ssh命令时,但在下一个ssh命令开始之前到达。

我警告不要ssh -t在无人看管的脚本中使用,例如crons。非交互式外壳程序要求远程命令以交互方式进行输入操作,这会引起各种麻烦。

您还可以在自己的Shell脚本中测试终端的存在。要使用较新版本的bash测试STDIN:

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

标准输出

  • 为别名sshssh -t,您可以期望在行尾获得额外的回车符。它可能对您不可见,但是在那里。它会显示为^M管道连接时的形式cat -e。然后,您必须付出额外的努力,以确保不会将此控制代码分配给变量,特别是如果要将输出插入数据库中时,尤其如此。
  • 程序还有一种风险,即程序会假定它们可以呈现对文件重定向不友好的输出。通常,如果您要将STDOUT重定向到文件,程序将识别出您的STDOUT不是终端,并忽略任何颜色代码。如果STDOUT重定向来自ssh客户端的输出,并且有一个与客户端的远程端相关联的PTY,则远程程序无法进行这种区分,并且最终将在输出文件中出现终端垃圾。将输出重定向到连接的远程端上的文件仍应按预期工作。

这是与之前相同的bash测试,但适用于STDOUT:

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

尽管可以解决这些问题,但您不可避免地会忘记围绕它们设计脚本。我们所有人都在某个时候做。您的团队成员可能也没有意识到/记住此别名,这会在他们编写使用您的别名的脚本时给您带来麻烦。

混叠sshssh -t非常多的地方,你会被违反的设计原则的情况下,至少惊喜 ; 人们将遇到他们未曾预料到的问题,并且可能不了解造成这些问题的原因。


9
一个人几乎给人的印象是,我曾在一支做到这一点的团队工作……
Andrew B

在此答案涵盖的范围内,这很棒。但是问题的范围更广,本质上是想了解所有差异(期望值)。附加信息:在进程级别,-t首先分配一个tty,然后运行外壳程序(沿途采购/ etc / profile和〜/ .bash_profile),然后运行命令。如果没有-t,ssh将INSTEAD源不同的env文件(/etc/bash.bashrc,然后是〜/ .bashrc),然后运行您的命令。这意味着您可以看到每种行为都有很大不同:$ PATH较短,可能是bash“一元”错误,因为您假设的ENV变量不存在...
Scott Prive

@Crossfit在另一个答案的评论中,我们讨论了登录外壳vs. non的主题,但是我们没有详尽地分析环境差异,因为OP已经考虑了针对其特殊需求的问题。请随时在您认为有余地的地方添加详细信息,因为这可能会对其他参与此问答的人有所帮助。
安德鲁B

33

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

还没有在其他的答案被提及一个优点是,工作时没有一个伪终端,所述SSH 转义字符~C不支持 ; 这使得程序可以安全地传输可能包含这些序列的二进制文件。

概念证明

使用伪终端复制二进制文件:

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

在不使用伪终端的情况下复制二进制文件:

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

这两个文件是不同的:

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

用伪终端复制的一个已损坏:

$ 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传输文件

这对于诸如scprsync使用SSH进行数据传输的程序特别重要。此的SCP协议如何工作的详细描述中解释了SCP协议如何由文本协议消息和二进制文件数据的混合物。


OpenSSH帮助保护您免受自己的伤害

值得注意的是,即使使用了该-t标志,OpenSSH ssh客户端如果检测到其stdin流不是终端,也将拒绝分配伪终端:

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

您仍然可以使用以下命令强制OpenSSH客户端分配伪终端-tt

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

在这两种情况下,(合理)不关心stdoutstderr重定向:

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

2
我没有考虑过非常有趣的一点,感谢您添加此答案!
珍妮·D

4

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

/etc/sudoers
...
Defaults requiretty

没有须藤

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

和与须藤

$ 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.

解决的办法是禁用转换换行符为回车换行stty -onlcr

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

1
很好,但是输出缩进了/:您是否知道是否可以自动回车(类似unix)?
Boop

1

考虑向后兼容性。

ssh的两种主要模式是带tty的交互式登录和不带tty的指定命令,因为它们分别是rlogin和的确切功能rsh。ssh需要提供rlogin/ rsh功能的超集才能成功替代。

因此,默认值是在ssh诞生之前确定的。必须使用新选项访问“我想指定命令获取tty”之类的组合。很高兴,至少我们这个选项现在,不像当我们使用rsh。我们并没有牺牲任何有用的功能来获得加密连接。我们有额外的功能!


0

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

这使您能够获得远程服务器的各种“外壳”。对于授予外壳程序访问权限但允许SSH的服务器(即Github是SFTP访问的已知示例),使用此标志将导致服务器拒绝您的连接。

该外壳程序还具有所有环境变量(例如$PATH),因此执行脚本通常需要tty才能起作用。


1
这不能回答问题。我已经知道如何分配伪tty。我想知道为什么我不应该总是分配一个。
Chas。欧文斯(Owens)2014年

1
@ Chas.Owens因为,正如我在答复中指出一些SSH服务器并不会允许TTY访问,如果你从服务器请求一个它会断开连接。
弥敦道C

5
我认为您可能会混淆一些术语。它不是仅由于与PTY相关联的外壳。通常有三种类型的外壳:non-interactiveinteractive,和loginlogin是其他两种外壳类型的另一个特征。这三个文件的排列决定了登录时将源文件,这又会影响环境的初始化方式。(变量,正如您所提到的)
Andrew B

3
@AndrewB你是对的...我也从这个问题中学到了一些东西。:)
Nathan C
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.