Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Paramiko中的单个会话中执行多个命令?(Python)_Python_Paramiko - Fatal编程技术网

如何在Paramiko中的单个会话中执行多个命令?(Python)

如何在Paramiko中的单个会话中执行多个命令?(Python),python,paramiko,Python,Paramiko,在paramiko中执行命令时,它总是在运行exec_命令时重置会话。 我希望能够执行sudo或su,并且在运行另一个exec_命令时仍然拥有这些特权。 另一个例子是尝试执行exec_命令(“cd/”),然后再次运行exec_命令并将其放在根目录中。我知道您可以执行类似exec_命令(“cd/;ls-l”)的操作,但我需要在单独的函数调用中执行。非交互式用例 这是一个非交互式的示例。。。它发送cd-tmp,ls,然后退出 def exec_command(self, command, bufsi

在paramiko中执行命令时,它总是在运行exec_命令时重置会话。 我希望能够执行sudo或su,并且在运行另一个exec_命令时仍然拥有这些特权。
另一个例子是尝试执行exec_命令(“cd/”),然后再次运行exec_命令并将其放在根目录中。我知道您可以执行类似exec_命令(“cd/;ls-l”)的操作,但我需要在单独的函数调用中执行。

非交互式用例

这是一个非交互式的示例。。。它发送
cd-tmp
ls
,然后
退出

def exec_command(self, command, bufsize=-1):
    #print "Executing Command: "+command
    chan = self._transport.open_session()
    chan.exec_command(command)
    stdin = chan.makefile('wb', bufsize)
    stdout = chan.makefile('rb', bufsize)
    stderr = chan.makefile_stderr('rb', bufsize)
    return stdin, stdout, stderr
交互式用例

如果你有一个交互式用例,这个答案不会有帮助。。。我个人会使用
pexpect
exscript
进行交互式会话。

严格来说,你不能。根据ssh规范:

会话是程序的远程执行。该程序可能是一个 shell、应用程序、系统命令或某些内置子系统


这意味着,一旦执行了命令,会话就完成了。不能在一个会话中执行多个命令。但是,您可以做的是启动一个远程shell(=一个命令),并通过stdin等与该shell交互。。。(考虑执行python脚本与运行交互式解释器)

尝试创建一个由
\n
字符分隔的命令字符串。这对我有用。
对于e、 g.
ssh.exec\u命令(“command\u 1\n command\u 2\n command\u 3”)

您可以通过在客户端上调用shell并发送命令来实现这一点。请参阅
该页面包含python 3.5的代码。我对代码进行了一些修改,使之适用于pythin 2.7。在此处添加代码以供参考

cmd = 'ls /home/dir'
self.ssh_stdin, self.ssh_stdout, self.ssh_stderr = self.ssh.exec_command(cmd)
print self.ssh_stdout.read()
cmd2 = 'cat /home/dir/test.log'
self.ssh_stdin2, self.ssh_stdout2, self.ssh_stderr2 = self.ssh.exec_command(cmd2)
print self.ssh_stdout2.read()

为了更好地使用,您可以执行整个BASH脚本文件,下面是代码:

import threading, paramiko

strdata=''
fulldata=''

class ssh:
    shell = None
    client = None
    transport = None

    def __init__(self, address, username, password):
        print("Connecting to server on ip", str(address) + ".")
        self.client = paramiko.client.SSHClient()
        self.client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
        self.client.connect(address, username=username, password=password, look_for_keys=False)
        self.transport = paramiko.Transport((address, 22))
        self.transport.connect(username=username, password=password)

        thread = threading.Thread(target=self.process)
        thread.daemon = True
        thread.start()

    def close_connection(self):
        if(self.client != None):
            self.client.close()
            self.transport.close()

    def open_shell(self):
        self.shell = self.client.invoke_shell()

    def send_shell(self, command):
        if(self.shell):
            self.shell.send(command + "\n")
        else:
            print("Shell not opened.")

    def process(self):
        global strdata, fulldata
        while True:
            # Print data when available
            if self.shell is not None and self.shell.recv_ready():
                alldata = self.shell.recv(1024)
                while self.shell.recv_ready():
                    alldata += self.shell.recv(1024)
                strdata = strdata + str(alldata)
                fulldata = fulldata + str(alldata)
                strdata = self.print_lines(strdata) # print all received data except last line

    def print_lines(self, data):
        last_line = data
        if '\n' in data:
            lines = data.splitlines()
            for i in range(0, len(lines)-1):
                print(lines[i])
            last_line = lines[len(lines) - 1]
            if data.endswith('\n'):
                print(last_line)
                last_line = ''
        return last_line


sshUsername = "SSH USERNAME"
sshPassword = "SSH PASSWORD"
sshServer = "SSH SERVER ADDRESS"


connection = ssh(sshServer, sshUsername, sshPassword)
connection.open_shell()
connection.send_shell('cmd1')
connection.send_shell('cmd2')
connection.send_shell('cmd3')
time.sleep(10)
print(strdata)    # print the last line of received data
print('==========================')
print(fulldata)   # This contains the complete data received.
print('==========================')
connection.close_connection()
这将在远程
192.168.1.101
Linux机器上执行本地
script.sh
文件

script.sh
(只是一个示例):


本教程对此进行了详细解释:。

您可以使用以下技术运行多个命令。使用分号分隔Linux命令 例如:


如果希望每个命令对下一个命令产生影响,应使用:

chan.exec_command("date;ls;free -m")
但在某些情况下,我发现当“;”不起作用时,使用“&&”就起作用了

stdin, stdout, stderr = client.exec_command("command1;command2;command3")

但此解决方案不允许在所有命令完成之前读取第一个命令的输出。我说的对吗?这不起作用,因为stdout.read()读取整个文件。也就是说,它将“键入”的程序读入终端。这不是预期的行为。如何只读取
ls
的输出,而不是整个程序和
ls
的输出?我同意上面的两条评论。。。有没有办法在所有命令完成之前读取一个命令的输出?@Mike Pennington嗨,伙计!谢谢你的回答,它实际上工作得很好,但是,sudo comands有一些问题,你能看看我的问题吗@MatthewMoisen:您应该使用exit命令作为最后一个命令。SSH RFC没有说明会话是否应该在执行命令后立即终止。如果您已经了解了大多数ssh客户端,那么在会话建立之后,它们会一直打开Exec/Shell。允许用户键入任何数字命令。当用户键入“退出”时,只有会话终止。您的意思是键入sendShell而不是send_shell吗?或者send_shell是您正在调用的paramiko.ssh类的内置项?@Fields,很好。我已经更新了代码。我忘了在ssh类中将sendShell重命名为send_shell。谢谢它的可能副本不是一个真正的bash脚本。您正在用户的默认shell中以命令的形式执行文件的内容。也可以通过这种方式使用
AutoAddPolicy
,您正在失去对MITM攻击的保护。@MartinPrikryl您能指出这样读取文件内容与执行BASH脚本之间的区别吗?我不明白您的评论与我的有什么关系。我是说您的代码不是在bash中执行命令,而是在用户的默认shell(可以是任何其他shell)中执行命令。您的代码将盲目地接受任何主机密钥,更糟糕的是,接受任何更改的主机密钥。因此,您的代码容易受到攻击。
cd Desktop
mkdir test_folder
cd test_folder
echo "$PATH" > path.txt
chan.exec_command("date;ls;free -m")
stdin, stdout, stderr = client.exec_command("command1;command2;command3")
stdin, stdout, stderr = client.exec_command("command1 && command2 && command3")