Python中的逐行远程数据传输

时间:2010-09-27 00:30:08

标签: python linux process ssh ipc

我一直在玩subprocess模块来迭代发送 输入文件中的每一行到由以下命令创建的进程。

ssh -t -A $host 'remote_command'

remote_command期望STDIN中的一行,对其进行一些处理 行并迭代循环直到STDIN关闭或达到EOF。

为实现这一目标,我一直在做的是:

process = subprocess.Popen("ssh -t -A $host 'remote_command'",
                           shell=True,
                           stdin=subprocess.PIPE)
for line in file('/tmp/foo'):
  process.stdin.write(line)
  process.stdin.flush()
process.stdin.close()

但我发现上述方法并不够健壮,因为它确实如此 通常情况是remote_command过早完成而不处理 整个内容(尽管有时相同的代码确实成功而没有问题)。

当我采用另一种方法时,情况是一样的,虽然非常类似:

process = subprocess.Popen("ssh -t -A $host 'remote_command'",
                           shell=True,
                           stdin=file('/tmp/foo'))

所以问题是:如何确保输入文件中的每一行都被Python中的远程机器发送,接收和处理直到最后?

4 个答案:

答案 0 :(得分:2)

如果这......

process = subprocess.Popen("ssh -t -A $host 'remote_command'",
                           shell=True,
                           stdin=subprocess.PIPE)
for line in file('/tmp/foo'):
    process.stdin.write(line)
    process.stdin.flush()
process.stdin.close()

...是你的整个计划,它不会(必然)有效。

尽管对process.stdin.close()的最终调用将确保在程序终止之前已将所有数据发送到ssh进程,但无法确保ssh进程已发送网络上的所有数据,因此可能会有一些未完成的数据要发送。

不幸的是,由于ssh进程是您程序的子进程,因此当您的程序终止时,ssh进程将收到一个SIGHUP,它会立即杀死它,可能在之前它完成了所有数据的发送。

只要remote_command在点击EOF时终止,就不会出现问题,您可以要求ssh进程忽略SIGHUP,然后继续在后台运行与...

process = subprocess.Popen("nohup ssh -t -A $host 'remote_command'", ...)

...或者让您的程序等待ssh进程完成,方法是添加...

process.wait()

...到你的程序结束。


<强>更新

经过进一步检查,如果某个流程的控制tty终止,而不是其父流程,则该流程看起来只会获得SIGHUP

这可能与-t选项有关,该选项在远程主机上创建一个新的控制tty,并且在它生成的子进程完成之前就已退出。

在这种情况下,您可能需要......

process = subprocess.Popen("ssh -t -A $host 'nohup remote_command'", ...)

...或者在没有-t选项的情况下尝试。

答案 1 :(得分:1)

您所做的不仅仅是为了确保所有输入都发送到您的子进程。在我看来,你的第二个例子比第一个好。您可以做的是检查子进程的返回代码。

return_code = p.wait()

您的远程命令应该在成功完成时返回0,如果发生错误则返回非零值。

答案 2 :(得分:0)

与使用paramiko之类的东西相比,你最好不要绕过子流程。

但在任何一种情况下,如果您在发送所有数据之前终止了连接,则可以捕获该异常,并且您将知道需要重试。如果进程过早死亡,您应该能够读取进程的退出代码。

答案 3 :(得分:0)

我想说最好的办法是使用回复管道来捕获远程命令的结果,并确保在每行之间和每行之间达到提示。 BTW我有时发现在远程链接会话结束时使用诸如ls -l之类的伪命令有助于确保在删除连接之前完成处理。