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

发布于 2024-11-11 16:24:21 字数 575 浏览 8 评论 0 原文

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

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

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

When executing a command in paramiko, it always resets the session when you run exec_command.
I want to able to execute sudo or su and still have those privileges when I run another exec_command.
Another example would be trying to exec_command("cd /") and then run exec_command again and have it be in the root directory. I know you can do something like exec_command("cd /; ls -l"), but I need to do it in separate function calls.

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

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

发布评论

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

评论(8

少女七分熟 2024-11-18 16:24:21

非交互式用例

这是一个非交互式示例...它发送cd tmpls,然后exit.

import sys
sys.stderr = open('/dev/null')       # Silence silly warnings from paramiko
import paramiko as pm
sys.stderr = sys.__stderr__
import os

class AllowAllKeys(pm.MissingHostKeyPolicy):
    def missing_host_key(self, client, hostname, key):
        return

HOST = '127.0.0.1'
USER = ''
PASSWORD = ''

client = pm.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()
stdin = channel.makefile('wb')
stdout = channel.makefile('rb')

stdin.write('''
cd tmp
ls
exit
''')
print stdout.read()

stdout.close()
stdin.close()
client.close()

交互式用例

如果您有交互式 ssh 用例,paramiko 可以处理它...我个人会使用 scrapli 驱动交互式 ssh 会话。

列出我能想到的交互使用 paramiko 的所有方法:

我可能错过了一些使用 的库paramiko,但应该清楚 paramiko 被控制 ssh 会话的 python 库广泛使用。

Non-Interactive use cases

This is a non-interactive example... it sends cd tmp, ls and then exit.

import sys
sys.stderr = open('/dev/null')       # Silence silly warnings from paramiko
import paramiko as pm
sys.stderr = sys.__stderr__
import os

class AllowAllKeys(pm.MissingHostKeyPolicy):
    def missing_host_key(self, client, hostname, key):
        return

HOST = '127.0.0.1'
USER = ''
PASSWORD = ''

client = pm.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()
stdin = channel.makefile('wb')
stdout = channel.makefile('rb')

stdin.write('''
cd tmp
ls
exit
''')
print stdout.read()

stdout.close()
stdin.close()
client.close()

Interactive use cases

If you have an interactive ssh use case, paramiko can handle it... I personally would drive interactive ssh sessions with scrapli.

Listing all the ways I can think of to use paramiko interactively:

I might have missed some libraries that use paramiko, but it should be clear that paramiko is used quite extensively by python libraries that control ssh sessions.

十级心震 2024-11-18 16:24:21

尝试创建一个由 \n 字符分隔的命令字符串。这对我有用。
为了。例如 ssh.exec_command("command_1 \n command_2 \n command_3")

Try creating a command string separated by \n character. It worked for me.
For. e.g. ssh.exec_command("command_1 \n command_2 \n command_3")

比忠 2024-11-18 16:24:21

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

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

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

Strictly speaking, you can't. According to the ssh spec:

A session is a remote execution of a program. The program may be a
shell, an application, a system command, or some built-in subsystem.

This means that, once the command has executed, the session is finished. You cannot execute multiple commands in one session. What you CAN do, however, is starting a remote shell (== one command), and interact with that shell through stdin etc... (think of executing a python script vs. running the interactive interpreter)

巴黎夜雨 2024-11-18 16:24:21

您可以通过在客户端上调用 shell 并发送命令来完成此操作。请参阅此处
该页面有 python 3.5 的代码。我对代码进行了一些修改以适用于 pythin 2.7。此处添加代码以供参考

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

You can do that by invoking shell on the client and sending commands. Please refer here
The page has code for python 3.5. I have modified the code a bit to work for pythin 2.7. Adding code here for reference

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()
少年亿悲伤 2024-11-18 16:24:21
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()
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()
荒路情人 2024-11-18 16:24:21

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

chan.exec_command("date;ls;free -m")

You can run multiple command using the below technique. Use semicolon to separate the Linux commands
Eg:

chan.exec_command("date;ls;free -m")
念﹏祤嫣 2024-11-18 16:24:21

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

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

但在某些情况下,我发现当“;”时不起作用,使用“&&”确实有效。

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

If you wish each command to have an effect on the next command you should use:

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

but in some cases, I found that when ";" doesn't work, using "&&" does work.

stdin, stdout, stderr = client.exec_command("command1 && command2 && command3")
烈酒灼喉 2024-11-18 16:24:21

您可以执行整个 BASH 脚本文件以便更好地使用,代码如下:

import paramiko

hostname = "192.168.1.101"
username = "test"
password = "abc123"

# initialize the SSH client
client = paramiko.SSHClient()
# add to known hosts
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
    client.connect(hostname=hostname, username=username, password=password)
except:
    print("[!] Cannot connect to the SSH Server")
    exit()

# read the BASH script content from the file
bash_script = open("script.sh").read()
# execute the BASH script
stdin, stdout, stderr = client.exec_command(bash_script)
# read the standard output and print it
print(stdout.read().decode())
# print errors if there are any
err = stderr.read().decode()
if err:
    print(err)
# close the connection
client.close()

这将在远程 192.168.1.101 Linux 计算机上执行本地 script.sh 文件。

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

cd Desktop
mkdir test_folder
cd test_folder
echo "$PATH" > path.txt

本教程详细解释了这一点:如何使用 Python 在远程计算机中执行 BASH 命令

You can execute an entire BASH script file for better use, here is the code for that:

import paramiko

hostname = "192.168.1.101"
username = "test"
password = "abc123"

# initialize the SSH client
client = paramiko.SSHClient()
# add to known hosts
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
    client.connect(hostname=hostname, username=username, password=password)
except:
    print("[!] Cannot connect to the SSH Server")
    exit()

# read the BASH script content from the file
bash_script = open("script.sh").read()
# execute the BASH script
stdin, stdout, stderr = client.exec_command(bash_script)
# read the standard output and print it
print(stdout.read().decode())
# print errors if there are any
err = stderr.read().decode()
if err:
    print(err)
# close the connection
client.close()

This will execute the local script.sh file on the remote 192.168.1.101 Linux machine.

script.sh (just an example):

cd Desktop
mkdir test_folder
cd test_folder
echo "$PATH" > path.txt

This tutorial explains this in detail: How to Execute BASH Commands in a Remote Machine in Python.

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