我正在使用paramiko在远程机器上通过ssh执行长时间运行的python脚本。工作就像一个魅力,到目前为止没有问题。
不幸的是,stdout(分别是stderr)只在脚本完成后显示!但是,由于执行时间的原因,我更倾向于在打印时输出每个新行,而不是之后。
remote = paramiko.SSHClient()
remote.set_missing_host_key_policy(paramiko.AutoAddPolicy())
remote.connect("host", username="uname", password="pwd")
# myScript produces continuous output, that I want to capture as it appears
stdin, stdout, stderr = remote.exec_command("python myScript.py")
stdin.close()
for line in stdout.read().splitlines():
print(line)
如何实现? 注意:当然可以通过另一个ssh会话将输出传输到文件并“减少”此文件,但这非常难看,我需要更清洁,理想的pythonic解决方案:)
答案 0 :(得分:10)
如read([size]) documentation中所述,如果您没有指定size
,则会在EOF之前读取,这会使脚本等到命令结束后再从read()
返回并打印任何输出。
请查看以下答案:How to loop until EOF in Python?和How to do a "While not EOF",了解如何耗尽类似文件的对象。
答案 1 :(得分:7)
我遇到了类似的问题。我能够通过向paramiko添加get_pty = True来解决它:
stdin, stdout, stderr = client.exec_command("/var/mylongscript.py", get_pty=True)
答案 2 :(得分:7)
如何使用this answer(在Python 3.6.1中测试)的最小且完整的工作示例
# run.py
from paramiko import SSHClient
ssh = SSHClient()
ssh.load_system_host_keys()
ssh.connect('...')
print('started...')
stdin, stdout, stderr = ssh.exec_command('python -m example', get_pty=True)
for line in iter(stdout.readline, ""):
print(line, end="")
print('finished.')
和
# example.py, at the server
import time
for x in range(10):
print(x)
time.sleep(2)
使用
在本地计算机上运行python -m run
答案 3 :(得分:2)
来自生成器函数的流式响应数据。
我想创建一个比标准 Client.exec_command() 示例更复杂且比我在 Channel.exec_command() 示例中看到的更复杂的类。另外,我还介绍了我遇到的一些“陷阱”。此摘要脚本已在 CentOS Stream - Python 3.6.8 上测试。
import sys
import paramiko
client = paramiko.SSHClient()
client.load_system_host_keys('/etc/ssh/ssh_known_hosts')
try:
client.connect('host', username='username', password='password',
port=22, timeout=2)
except Exception as _e:
sys.stdout.write(_e)
# is_active can be a false positive, so further test
transport = client.get_transport()
if transport.is_active():
try:
transport.send_ignore()
except Exception as _e:
sys.stdout.write(_e)
sys.exit(1)
else:
sys.exit(1)
channel = transport.open_session()
# We're not handling stdout & stderr separately
channel.set_combine_stderr(1)
channel.exec_command('whoami')
# Command was sent, no longer need stdin
channel.shutdown_write()
def responseGen(channel):
# Small outputs (i.e. 'whoami') can end up running too quickly
# so we yield channel.recv in both scenarios
while True:
if channel.recv_ready():
yield channel.recv(4096).decode('utf-8')
if channel.exit_status_ready():
yield channel.recv(4096).decode('utf-8')
break
# iterate over each yield as it is given
for response in responseGen(channel):
sys.stdout.write(response)
# We're done, explicitly close the conenction
client.close()
答案 4 :(得分:1)
使用此:
stdin, stdout, stderr = ssh.exec_command('python -m example', get_pty=True)
for line in iter(stdout.readline, ""):
print(line, end="")
来自@JorgeLeitao的答案使我的stdout输出加速到几乎实时!
我正在使用:
stdin, stdout, stderr = ssh.exec_command(cmd)
for line in stdout:
# Process each line in the remote output
print (line)