使用 Python 的 Paramiko 自动连接和执行程序

Automate ssh connection and execution of program with Python's Paramiko

我想使用 python 自动执行特定任务。
此任务包括使用 ssh 连接到远程服务器以及 运行 特定程序(称之为 prog.out), 可能会或可能不会要求用户输入.
经过一些研究和权衡我的选择后,我决定使用 Python 的 Paramiko(考虑到以下情况,这可能是错误的……)。

让我们从 prog.out 不询问任何输入的简单可能性开始,而只是将一些信息打印到控制台:

int main(int argc, char* argv[]) {

        printf("Hey there, fella\n");
        printf("How are you this morning?\n");
        printf("See ya...\n");

        return 0;
}

编译为:prog.out,并位于 server_name,等待执行。
所以在那种情况下:

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("server_name")
sin, sout, serr = client.exec_command('./prog.out')

for line in sout.readlines():
    print(line, end = '')

将工作得很好,并且会打印出 prog.out 产生的任何内容。
但是如果 prog.out 是:

int main(int argc, char* argv[]) {

        printf("Hey there, fella\n");
        printf("How are you this morning?\n");
        printf("please enter an integer...\n");
        int a;
        scanf("%d", &a);
        printf("you entered %d\n", a);
        printf("see ya...\n");

        return 0;
}

然后上面的 python 代码将阻塞在 sout.readlines()(等待 eof?)...
避免在 sout.readlines() 中阻塞的方法是通过写入其标准输入管道向 prog.out 提供输入:

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("server_name")
sin, sout, serr = client.exec_command('./prog.out')

sin.write('55\n')

for line in sout.readlines():
    print(line, end = '')

但我无法提前知道 prog.out 是否需要用户输入...
我正在寻找一种稳健的方式 运行 prog.out 并让用户根据需要与其进行交互。 prog.out 需要输入时是否有一些指示?

编辑

好的,我做了一点实验,发现只要 prog.out 还没有退出,任何从通道读取 read() 的尝试都会被阻塞,但是 prog.out 不能只要没有提供输入就退出...
为什么我无法读取 prog.out 已经发送的字节,即使它还没有完成?
我真的很想模拟用户,就好像他或她直接与 prog.out...

交互一样

有一个基于 Paramiko 构建的库可能更适合您的需要。

我说的是 python fabric(与我无关)

Fabric is a Python (2.5-2.7) library and command-line tool for streamlining the use of SSH for application deployment or systems administration tasks.

It provides a basic suite of operations for executing local or remote shell commands (normally or via sudo) and uploading/downloading files, as well as auxiliary functionality such as prompting the running user for input, or aborting execution.

如果我没有正确理解您的要求,您的代码可能如下所示。

from fabric.api import run

@task
def run_a_out()
    run('echo "some input for a.out" | ./a.out')

然后您将使用

执行远程程序
    fab --hosts=someserver run_a_out

如果您想动态控制 get 传递给 a.out 的内容,您可以向 run_a_out() 添加一个参数并从命令行传递它。

简而言之,Fabric 为 paramiko 提供了更高级别 API,其中大部分复杂性都被隐藏了。