Python逐行远程数据传输

发布于 2024-09-24 20:42:46 字数 910 浏览 4 评论 0原文

我一直在使用 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 中?

I've been playing with the subprocess module to iteratively send
each line in an input file to a process created by the following command.

ssh -t -A $host 'remote_command'

The remote_command expects a line in its STDIN, does some processing on the
line and iterates the cycle until STDIN closes or reaches EOF.

To achieve this, what I'd been doing was:

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()

But what I discovered was that the above method is not robust enough, as it is
often the case that remote_command finishes prematurely without processing the
entire content (though sometimes the same code does succeed without a problem).

The situation is the same when I employ another, albeit very simiar, approach:

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

So the question is: How can I make sure that each line in an input file be sent, received, and processed until the end by the remote machine in Python?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

╄→承喏 2024-10-01 20:42:46

如果这......

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 选项。

If this...

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()

...is your entire program, it won't (necessarily) work.

Although the final call to process.stdin.close() will ensure that all the data has been sent to the ssh process before your program terminates, it won't ensure that the ssh process has sent all the data across the network, so there may well be some outstanding data for it to send.

Unfortunately, since the ssh process is a child process of your program, then when your program terminates, the ssh process will receive a SIGHUP which will immediately kill it, potentially before it finishes sending all its data.

As long as the remote_command terminates when it hits EOF, it's not a problem, and you can either ask the ssh process to ignore the SIGHUP, and continue running in the background with...

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

...or ask your program to wait for the ssh process to finish, by adding...

process.wait()

...to the end of your program.


Update

Upon further examination, it looks like a process only gets a SIGHUP if its controlling tty terminates, not its parent process.

It may be something to do with the -t option which creates a new controlling tty on the remote host, and that's exiting before the subprocess it spawns has finished.

In which case, you might need...

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

...or try it without the -t option.

南烟 2024-10-01 20:42:46

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

return_code = p.wait()

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

You can't do much more than what you have done to make sure that all input gets sent to your child process. Your second example is better than the first one, in my opinion. What you can do is inspecting the return code from your child process.

return_code = p.wait()

Your remote command should probably return 0 on successful completion and something non zero if an error occurred.

耶耶耶 2024-10-01 20:42:46

您可能最好使用 paramiko 之类的东西,而不是围绕子流程。

但无论哪种情况,如果您的连接在发送所有数据之前终止,您可以捕获该异常,并且您会知道需要重试。如果进程过早终止,您应该能够读取进程的退出代码。

Instead of wrapping around a subprocess, you'd likely be better off using something like paramiko.

But in either case, if your connection gets terminated before you've sent all your data, you can catch that exception and you'll know that you need to retry. In the event the process dies prematurely you should be able to read the exit-code of the process.

小姐丶请自重 2024-10-01 20:42:46

我想说你最好的选择是使用回复管道来捕获远程命令的结果,并确保你在行之间和每行之后到达提示。顺便说一句,我有时发现远程链接会话结束时的虚拟命令(例如 ls -l)有助于确保在断开连接之前完成处理。

I would say your best bet would be to use the reply pipe to capture the results of the remote command and ensure that you reach a prompt between lines and after each line. BTW I have sometimes found that a dummy command such as ls -l at the end of a remote link session helps to ensure that processing is finished before dropping the connection.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文