我可以在python的日志文件中捕获远程执行的命令及其输出吗?

时间:2011-11-11 03:56:54

标签: python

我正在使用paramiko在python中执行远程命令。我想将完整的远程命令行详细信息记录到日志文件中。

e.g。就像在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()解决了上述问题 e.g。

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;退出\ 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 :(得分:3)

paramiko.SSHClient文档看起来,您可以使用recv_ready和recv返回shell / channel的结果。例如,这对我有用:

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

答案 1 :(得分:0)

以下是如何使用fabricparamiko以及更高级别的高级包装器)捕获远程执行命令的输出:

#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包含lswwho命令的输出。