如何用脚本模拟终端输入

wen 实用脚本 2

本文目录导读:

如何用脚本模拟终端输入

  1. 使用 pexpect (Python)
  2. 使用 subprocess (Python)
  3. 使用 expect (Shell)
  4. 使用 Python 的 basic 方法
  5. 使用 tmux/screen 模拟
  6. 高级 pexpect 示例
  7. Python + pty 完整示例
  8. 最佳实践建议:

使用 pexpect (Python)

最常用的方法,可以模拟终端交互:

import pexpect
# 启动一个程序
child = pexpect.spawn('bash')
# 等待提示符出现
child.expect(r'\$')
# 发送命令
child.sendline('echo "Hello World"')
child.expect(r'Hello World')
child.sendline('exit')
# 交互式控制
child = pexpect.spawn('ssh user@host')
child.expect('password:')
child.sendline('mypassword')
child.expect(r'\$')
child.sendline('ls -la')

使用 subprocess (Python)

import subprocess
import time
# 方式1:直接执行
result = subprocess.run(['echo', 'hello'], capture_output=True, text=True)
print(result.stdout)
# 方式2:管道交互
process = subprocess.Popen(
    ['python3', '-i'],  # 启动交互式Python
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    text=True
)
process.stdin.write("print('hello')\n")
process.stdin.flush()
time.sleep(1)
# 读取输出
output = process.stdout.readline()
print(output)

使用 expect (Shell)

#!/usr/bin/expect -f
# 启动交互程序
set timeout 10
spawn ssh user@host
# 等待密码提示
expect "password:"
send "mypassword\r"
# 等待命令提示符
expect "$"
send "ls -la\r"
# 发送多个命令
expect "$"
send "cd /tmp\r"
expect "$"
send "echo 'test' > file.txt\r"
# 退出
expect "$"
send "exit\r"
expect eof

使用 Python 的 basic 方法

import os
import pty
import select
import subprocess
def interactive_terminal():
    # 创建伪终端
    master, slave = pty.openpty()
    # 启动bash
    process = subprocess.Popen(
        ['bash'],
        stdin=slave,
        stdout=slave,
        stderr=slave,
        close_fds=True
    )
    # 发送命令
    os.write(master, b'echo "Hello"\n')
    # 读取输出
    while True:
        r, _, _ = select.select([master], [], [], 0.1)
        if r:
            output = os.read(master, 1024)
            print(output.decode(), end='')
        if process.poll() is not None:
            break

使用 tmux/screen 模拟

#!/bin/bash
# 使用 tmux 模拟终端输入
# 创建新会话
tmux new-session -d -s mysession
# 发送命令
tmux send-keys -t mysession "echo 'Hello'" Enter
# 发送多行命令
tmux send-keys -t mysession "for i in 1 2 3; do echo \$i; done" Enter
# 读取输出
tmux capture-pane -t mysession -p
# 退出会话
tmux kill-session -t mysession

高级 pexpect 示例

import pexpect
import re
class TerminalEmulator:
    def __init__(self, command):
        self.child = pexpect.spawn(command, encoding='utf-8')
        self.child.logfile = open('terminal.log', 'w')
    def execute(self, command, expected_pattern=None, timeout=10):
        """执行命令并等待结果"""
        self.child.sendline(command)
        if expected_pattern:
            try:
                self.child.expect(expected_pattern, timeout=timeout)
                return self.child.before + self.child.after
            except pexpect.TIMEOUT:
                return f"命令超时: {command}"
        else:
            self.child.expect(pexpect.EOF, timeout=timeout)
            return self.child.before
    def interact(self):
        """进入交互模式"""
        print("进入交互模式,按 Ctrl+] 退出")
        self.child.interact()
# 使用示例
if __name__ == "__main__":
    term = TerminalEmulator('bash')
    # 执行命令
    result = term.execute('ls -la', expected_pattern=r'total|找不到|error')
    print("命令执行结果:", result)
    # 执行复杂命令
    result = term.execute(
        'python3 -c "import sys; print(sys.version)"',
        expected_pattern=r'Python'
    )
    print("Python版本:", result)

Python + pty 完整示例

import os
import pty
import subprocess
import time
class PTYTerminal:
    def __init__(self, command):
        self.master, self.slave = pty.openpty()
        self.process = subprocess.Popen(
            command,
            stdin=self.slave,
            stdout=self.slave,
            stderr=self.slave,
            close_fds=True
        )
        os.close(self.slave)
    def send_command(self, command):
        os.write(self.master, command.encode() + b'\n')
    def read_output(self, timeout=1):
        output = b''
        end_time = time.time() + timeout
        while time.time() < end_time:
            import select
            r, _, _ = select.select([self.master], [], [], 0.1)
            if r:
                try:
                    data = os.read(self.master, 1024)
                    if not data:
                        break
                    output += data
                except OSError:
                    break
        return output.decode()
    def close(self):
        self.process.terminate()
        os.close(self.master)
# 使用示例
term = PTYTerminal(['bash'])
term.send_command('echo "Test"')
time.sleep(0.5)
output = term.read_output()
print("收到的输出:", output)
term.close()

最佳实践建议:

  1. 对于简单任务:使用 subprocess
  2. 需要交互:使用 pexpect
  3. 需要完全模拟终端:使用 ptytmux
  4. 测试场景:使用 pexpectexpect 写测试脚本

这些方法能有效模拟终端输入,适用于自动化测试、教学演示、批量操作等场景。

抱歉,评论功能暂时关闭!