【问题标题】:basic paramiko exec_command help基本 paramiko exec_command 帮助
【发布时间】:2011-08-09 20:57:08
【问题描述】:

我是新的 paramiko 用户,在使用 paramiko 的远程服务器上运行命令时遇到困难。我想导出一个路径并在后台运行一个名为tophat 的程序。我可以使用paramiko.sshclient() 正常登录,但我的exec_command 代码没有结果。

stdin, stdout, sterr = ssh.exec_command('export PATH=$PATH:/proj/genome/programs
/tophat-1.3.0/bin:/proj/genome/programs/cufflinks-1.0.3/bin:/proj/genome/programs/
bowtie-0.12.7:/proj/genome/programs/samtools-0.1.16')

stdin, stdout, sterr = ssh.exec_command('nohup tophat -o /output/path/directory -I 
10000 -p 8 --microexon-search -r 50 /proj/genome/programs/bowtie-0.12.7/indexes
/ce9 /input/path/1 /input/path/2 &')

没有nohup.out 文件,python 只是转到下一行,没有错误消息。我也试过不使用nohup,结果是一样的。我试图关注this paramiko tutorial

我是否错误地使用了exec_command

【问题讨论】:

  • 第二个命令在与第一个不同的 shell 中运行,因此export 将无效。
  • 您最好将环境变量放在一行中。即:ssh.exec_command('PATH=/bin:/usr/bin:etcetera nohup ...');这将只为单个命令导出它,这正是您想要的。

标签: python paramiko


【解决方案1】:

我也遇到了同样的问题,查看this articlethis answer 后,我看到解决方案是调用Channel 的recv_exit_status() 方法。这是我的代码:

import paramiko
import time

cli = paramiko.client.SSHClient()
cli.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
cli.connect(hostname="10.66.171.100", username="mapping")
stdin_, stdout_, stderr_ = cli.exec_command("ls -l ~")
# time.sleep(2)    # Previously, I had to sleep for some time.
stdout_.channel.recv_exit_status()
lines = stdout_.readlines()
for line in lines:
    print line

cli.close()

现在我的代码将被阻止,直到远程命令完成。这个方法在here有解释,请注意警告。

【讨论】:

  • 这对我有用,最好通过删除每行末尾的分号来使输出更加 Pythonic。
  • @IgnacioTartaull 删除了分号。当我写上面的代码时,我只是从 C++ 转向 Python。 :-)
【解决方案2】:

exec_command() 是非阻塞的,它只是将命令发送到服务器,然后 Python 将运行以下代码。

我认为你应该等待命令执行结束,然后再做剩下的工作。

“time.sleep(10)”可以帮助需要“导入时间”。 一些例子表明你可以从stdout ChannelFile 对象中读取,或者简单地使用stdout.readlines(),它似乎读取了来自服务器的所有响应,猜猜这可能帮助。

您的代码,上面两行 exec_command,它们实际上是在不同的 exec 会话中运行。我不确定这对您的情况是否有影响。

我建议你看看 demos 文件夹中的演示,它们使用 Channel 类,它有更好的 API 来为 shell 和 exec 进行阻塞/非阻塞发送。

【讨论】:

  • 我遇到了类似的问题,我只是想插话说 stdout.readlines() 对我很有用。它迫使我的脚本等到 exec_command() 完成运行后再继续。谢谢!
【解决方案3】:

您最好在运行命令之前加载 bash_profile。否则,您可能会收到“找不到命令”异常。

例如,我写了command = 'mysqldump -uu -pp -h1.1.1.1 -P999 table > table.sql'这个命令,目的是为了转储一个Mysql表

然后我必须在转储命令之前手动加载 bash_profile,方法是键入 . ~/.profile; .~/.bash_profile;

示例

my_command  = 'mysqldump -uu -pp -h1.1.1.1 -P999 table > table.sql;'

pre_command = """
. ~/.profile;
. ~/.bash_profile;
"""

command = pre_command + my_command

stdin, stdout, stderr = ssh.exec_command(command)

【讨论】:

  • 不,您最好运行一个不需要来自您的.profile 或其他交互式shell 启动文件的任何内容的命令。当您愚蠢地定义时,这是一种解决方法,例如启动文件中的别名或需要运行不在PATH 中的命令;但前者的解决方法是干脆不这样做(以普通方式拼出命令而不是尝试使用别名),而后者则将完整路径传递给命令(例如/usr/lib/sendmail 而不仅仅是sendmail )。