我可以在Python中捕获远程执行的命令及其输出到日志文件中吗?
我正在用paramiko在Python中执行远程命令。我想把完整的远程命令行细节记录到日志文件里。
比如,像在perl中使用Expect那样,我们可以把下面的命令和它的输出记录到日志文件中。
samir@ssahoo-ub-in:~$ cat logfile.txt
samir@ssahoo-ub-in:~$ ls
Desktop Documents Downloads examples.desktop getskype-linux-beta-ubuntu-64 Music Pictures Public Templates Videos VirtualBox VMs
samir@ssahoo-ub-in:~$ hostname
ssahoo-ub-in
samir@ssahoo-ub-in:~$ w
09:11:12 up 10:26, 6 users, load average: 0.05, 0.05, 0.06
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
samir tty7 :0 22:45 10:26m 12:51 0.23s gnome-session --session=classic-gnome
samir pts/0 :0.0 22:46 10:24m 32.80s 14.34s gnome-terminal
samir pts/1 :0.0 23:49 1:03m 0.57s 0.57s bash
samir pts/2 :0.0 07:42 1:22m 0.48s 0.09s vim ../projects /test/test_cases/common/TestHostname.py
samir pts/3 :0.0 08:11 0.00s 0.57s 0.01s w
samir pts/4 :0.0 08:24 46:08 0.21s 0.04s python
samir@ssahoo-ub-in:~$ who
samir tty7 2011-11-10 22:45 (:0)
samir pts/0 2011-11-10 22:46 (:0.0)
samir pts/1 2011-11-10 23:49 (:0.0)
samir pts/2 2011-11-11 07:42 (:0.0)
samir pts/3 2011-11-11 08:11 (:0.0)
samir pts/4 2011-11-11 08:24 (:0.0)
samir@ssahoo-ub-in:~$
我通过使用paramiko.invoke_shell()解决了上面的问题。
client = paramiko.SSHClient()
client.load_system_host_keys()
client.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
client.set_missing_host_key_policy(AllowAllKeys())
client.connect(HOST, username=USER, password=PASSWORD)
channel = client.invoke_shell()
channel.send("ls -l\n")
while not channel.recv_ready():
time.sleep(2)
results += channel.recv(1024)
但是,有人能帮我获取标准输出(stdout)、标准错误(stderr)和返回代码(退出状态)吗?
我在调用shell后尝试使用recv_stderr和recv_exit_status。但是当我尝试打印stderr和退出状态时,它什么也不打印。以下是我的代码:
import paramiko, time
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('localhost', username='sam', password='mypassword')
channel = ssh.invoke_shell()
results = ''
results2 = ''
password = 'my_root_password'
try:
channel.send("su -\n")
while not channel.recv_ready():
print "Waiting for root challenge..."
time.sleep(2)
results += channel.recv(1024)
channel.send("%s\n" % password)
while not channel.recv_ready():
print "Authenticating..."
time.sleep(2)
results += channel.recv(1024)
channel.send("ls file_doesnt_exist\n") # Here I am sending a wrong command to fail
if channel.exit_status_ready():
result3 = channel.recv_exit_status(1024)
print "exit status is:", results3 # It doesnt return anything
if channel.recv_stderr_ready():
result2 = channel.recv_stderr(1024)
print results2 # Doesn't print error
except Exception, e:
print e
我在返回代码上遇到了一些问题。可能是我没有正确使用。每次我打印返回代码时,它都和第一次返回的一样。难道我需要重置返回代码吗?在下面的例子中,我对两个命令的返回代码都是2。现在当我交换这两个命令,也就是把'ls -al;exit\n'替换成'ls -al file_not_exist;exit\n',反之亦然,它却打印返回代码0。每次它都打印和第一次返回的一样的返回代码。
channel = client.invoke_shell()
channel.send('ls -al file_not_exist;exit\n') #Sending to list a file which doesn't exist
time.sleep(3)
print "My 1st command exit status is: ",channel.exit_status_ready()
print "My 1st command return code is: ", channel.recv_exit_status()
channel.send('ls -al;exit\n')
time.sleep(3)
print "My 2nd command exit status is: ",channel.exit_status_ready()
print "My 2nd command return code is: ",channel.recv_exit_status()
我需要打印每个命令的返回代码。你能帮我解决这个问题吗?
2 个回答
0
下面是如何使用fabric
(这是一个在paramiko
等基础上构建的高级工具)来捕获远程执行命令的输出:
#file: fabfile.py
import functools
import logging
import sys
from fabric.api import run, hide
def do_stuff():
for cmd in ['ls', 'w', 'who']:
run(cmd)
# configure logging
logger = logging.getLogger("logged")
logger.setLevel(logging.INFO)
logger.addHandler(logging.FileHandler('logfile.txt'))
def logged(func):
"""Logging decorator."""
@functools.wraps(func)
def wrapper(*args, **kwargs):
with hide('output'):
output = func(*args, **kwargs)
logger.info(output)
return output
return wrapper
run = logged(run)
示例
$ fab do_stuff -H localhost
[localhost] Executing task 'do_stuff'
[localhost] run: ls
[localhost] run: w
[localhost] run: who
Done.
Disconnecting from localhost... done.
而logfile.txt
文件中包含了ls
、w
和who
命令的输出结果。
3
看起来根据 paramiko.SSHClient 的文档,你可以使用 recv_ready 和 recv 来获取 shell 或通道的结果。例如,这段代码对我有效:
client = SSHClient()
lient.load_system_host_keys()
client.set_missing_host_key_policy(AllowAllKeys())
client.connect(HOST,username=USERNAME,password=PASSWORD)
channel = client.invoke_shell()
channel.send('ls\n')
while channel.recv_ready():
channel.recv(1024)
channel.send('exit\n')
if channel.exit_status_ready():
print channel.recv_exit_status()