“在没有paramiko的情况下通过python运行ssh时,不会分配伪终端,因为stdin不是终端”

 2019-09-09 

“Pseudo-terminal will not be allocated because stdin is not a terminal” when running ssh through python without paramiko

我在Python中运行ssh而不使用像Paramiko这样的外部库。 我有理由这样做,而不是通过外部库。

基本上我在做subprocess.Popen("ssh -t bla -- command")

这样做时我收到以下消息:

1
Pseudo-terminal will not be allocated because stdin is not a terminal.

我用-t运行它的原因是我希望远程命令在我杀死我的python脚本时终止。

当我尝试使用-t -t(强制它)时,我收到以下消息:

1
tcgetattr: Inappropriate ioctl for device

有没有办法可以通过Python运行带有-t的ssh命令?


我可以恭敬地建议您提出错误的问题,并且正确的问题可能类似于"如何在我的python程序终止时确保子进程终止"

你可以做一些聪明的unix东西,比如分配一个pty,并确保你的子进程使用它作为std in out等,这样ssh命令认为??它正在与终端而不是管道通话,但这可能不是你的真的很想做。


要在python脚本被终止时终止远程命令,您可以(作为ssh-t选项的替代)实现一个变通方法,当stdin为正在关闭(参见Bug 396 - 未分配pty时sshd孤立进程)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# sample code in Bash

# press ctrl-d for EOF
ssh localhost '
TUBE=/tmp/myfifo.fifo
rm -f"$TUBE"
mkfifo"$TUBE"
#exec 3<>"$TUBE"

<"$TUBE" sleep 100 &  appPID=$!

# cf."OpenSSH and non-blocking mode",
# http://lists.mindrot.org/pipermail/openssh-unix-dev/2005-July/023090.html
#cat >"$TUBE"
#socat -u STDIN"PIPE:$TUBE"
dd of="$TUBE" bs=1 2>/dev/null
#while IFS="" read -r -n 1 char; do printf '
%s'"$char"; done >"$TUBE"

#kill -HUP -$appPID
kill $appPID

rm -f"$TUBE"
'


听起来你真的要求旧nohup命令的反转;也就是说某种方法可以确保远程命令响应TTY(PTY或伪相 - tty)驱动程序在关闭它的底层连接时产生的HUP(挂起)信号。

就我个人而言,我怀疑Paramiko要比使用子进程模块管理它要好得多。你可以让Paramiko打开连接,分配pty并执行你的命令而不会有任何瑕疵;并且使用现有的known_hosts和身份文件(私钥)的代码相对简单。

此配方使用ActiveState中的paramiko通过SSH复制文件显示了加载ssh known_hosts的基础知识,使用身份文件并与您可能正在运行的任何ssh代理进行交互。从那里你要求的应该只是一个问题:

  • 创建会话,
  • 创建一个频道,
  • 得到一个pty
  • 并执行您的远程命令或调用shell并使用stdin文件将您的命令发送到该shell,就像它返回的对象一样。

您还可以使用SSH协议的TwistedConch实现。但是,绕过Twisted编程框架,可能会更加困难。

以下是Twisted中一个简单的ssh服务器的示例,支持pty:60秒内扭曲的海螺:PTY请求
这是你的帖子发布前一周的SO线程在Twisted中通过ssh运行远程命令的最佳方法?但这根本不包括pty相关问题。查看twisted.conch.ssh.session的文档表明它有支持;但将其列为"未记录的"。

当然,您甚至可以使用Pexpect,将shell生成到本地ssh客户端并通过它发送远程命令。这将最接近地模拟从您自己的shell运行命令的方式。