【问题标题】:can't make ssh connection via python无法通过 python 建立 ssh 连接
【发布时间】:2017-03-13 14:19:24
【问题描述】:

我关注了这个question 我在 PostgreSQL 中有这个功能:

CREATE OR REPLACE FUNCTION a()
  RETURNS void AS
$BODY$
import subprocess
cmd1 = "usr/bin/ssh usera@192.168.10.5 time"
out1, err1 = subprocess.Popen(cmd1,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE).communicate()
plpy.notice(out1)
$BODY$
  LANGUAGE plpythonu VOLATILE

这应该登录到指定的服务器并显示其time。 无论我做什么,我总能得到:

错误:OSError:[Errno 2] 没有这样的文件或目录

我没有得到错误的唯一一次是如果 cmd1 = "usr/bin/ssh" 但它什么也没做。

我怎样才能让它工作?

【问题讨论】:

  • 我认为ssh 命令的路径应该以根文件夹-/usr/bin/ssh 开头。如果没有前导斜杠,它将是一个相对路径 - 也许这就是引发“没有这样的文件或目录”错误的原因。
  • cmd1 应该更像:cmd1 = ['/usr/bin/ssh', 'usera@192.168.10.5', 'time']。这是(如果我没记错的话)因为Popen() 假定命令参数是一个列表,除非危险地提供shell=True。你也可以使用cmd1 = shlex.split("/usr/bin/ssh usera@192.168.10.5 time")
  • @Torxed 这可以防止错误但是没有任何东西打印到屏幕上
  • @avi 很可能是因为运行脚本的主机不允许在没有密码的情况下进行 SSH - 或者 plpy.notice() 不是字符串?如果 SSH 挂起等待密码,.communicate() 也将挂起并按照文档中的描述等待:Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. >>>Wait for process to terminate.<<<。您是否尝试过从服务器手动运行此命令一次,看看会发生什么?

标签: python postgresql ssh


【解决方案1】:

您面临的问题是Popen() 假定命令是命令+参数的列表。

因此,cmd1 应该看起来更像:

cmd1 = ['/usr/bin/ssh', 'usera@192.168.10.5', 'time']

(除非危险地提供shell=True,那么你可以保持你的命令字符串不变)。

你也可以使用:

import shlex
cmd1 = shlex.split("/usr/bin/ssh usera@192.168.10.5 time")

这也包含在Popen() 的文档中。

最后的注意事项:我从未使用过plpythonu 或此 SQL 版本的代码执行,但我假设您希望指定 SSH 的完整路径,正如 Lix 指出的那样,那是/usr/bin/ssh 而不是usr/bin/ssh。但您的主要问题是如何将参数传递给Popen()

不要忘记允许 SSH 使用密钥登录,否则命令可能会在后台要求输入密码时挂起。

看到很多人在运行系统命令时遇到问题而程序员不明白为什么会挂起,请尝试以下修改以在命令执行而不是结束时获得输出(.communicate() 将等待 EOL,这意味着如果该过程永远不会退出):

CREATE OR REPLACE FUNCTION a()
  RETURNS void AS
$BODY$
import subprocess
cmd1 = ["usr/bin/ssh", "usera@192.168.10.5", "time"]
process = subprocess.Popen(cmd1,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.STDOUT).communicate()
while process.poll() is None:
    plpy.notice(process.stdout.readline())
$BODY$
  LANGUAGE plpythonu VOLATILE

它仍然非常低效,因为我将 STDERR 和 STDOUT 融合在一起并使用readline() 而不是read()import select 也可能在这里有用。

但这会让你从命令中“实时”输出,而不是在最后隐藏起来。它还应该打印命令抛出的任何错误(但仍然挂起,因为错误没有正确关闭应用程序)。

这是一个常见的错误,人们应该阅读更多关于此的示例/文档。

【讨论】:

  • 我实际上并不需要命令是字符串。我将使用列表方法。如何知道选项是否成功是否有任何错误代码?
  • @avi 我建议你试试代码,看看是否有任何错误。我给出的最后一次编辑应该打印任何错误。如果有,请更正它们。但是我无法提前知道是否会有任何错误^^ 如果它不起作用,我建议您针对该特定问题创建一个新问题,因为这是Popen() 使用问题线程:)
猜你喜欢
  • 2017-06-24
  • 1970-01-01
  • 1970-01-01
  • 2021-12-02
  • 1970-01-01
  • 2018-07-28
  • 1970-01-01
  • 2018-08-14
  • 1970-01-01
相关资源
最近更新 更多