如何用Python处理子Shell并执行指定命令(含sccli示例)
用Python自动化操作CDMA SoftCore CLI及交互式Shell通用方案
嘿,刚好做过不少这类运维自动化的活儿,直接给你上代码和思路——用pexpect库就能完美搞定交互式Shell的操作,这玩意儿就是专门对付这种需要手动敲命令等提示符的场景的。
一、针对你需求的具体实现代码
首先得先装依赖:
pip install pexpect
然后是实现你那一套流程的代码,每一步都加了注释,一看就懂:
import pexpect import os def automate_cdma_sccli(): # 1. 切换到目标目录 os.chdir("/opt/cdma-msc/") # 2. 启动sccli交互式Shell # spawn()用来启动一个子进程,相当于手动在终端敲./sccli cli_child = pexpect.spawn("./sccli") try: # 3. 等待RAN>提示符出现,超时10秒(根据实际情况调整) cli_child.expect("RAN>", timeout=10) # 发送show system命令,sendline会自动加换行,模拟回车 cli_child.sendline("show system") # 等待命令执行完成,再次出现RAN>提示符 cli_child.expect("RAN>", timeout=10) # 提取命令输出:before属性存的是上次expect匹配到的内容之前的所有输出 system_config = cli_child.before.decode("utf-8") print("=== 获取到的系统配置 ===") print(system_config) # 4. 发送exit命令退出Shell cli_child.sendline("exit") # 等待进程完全退出 cli_child.wait() except pexpect.TIMEOUT: print("错误:等待提示符超时,可能程序启动慢或者命令执行耗时太长") cli_child.close() except pexpect.EOF: print("错误:Shell提前退出,可能程序运行出错了") if __name__ == "__main__": automate_cdma_sccli()
二、交互式Shell处理的通用方法
其实不管是sccli还是你提到的rancli,处理逻辑都是一样的,核心就是启动进程→等待特定提示符→发送命令→等待结果→重复/退出,关键点:
pexpect.spawn(cmd):启动目标进程,返回一个子进程对象,用来操控交互child.expect(pattern):等待输出中出现指定的模式(可以是字符串、正则或者列表),匹配到才继续执行child.sendline(cmd):发送命令并自动加换行,和手动敲完命令回车效果一样child.before:获取上次expect匹配成功之前的所有输出,这就是你要的命令结果- 异常处理:一定要处理
TIMEOUT(等太久没拿到提示符)和EOF(进程意外退出)的情况,避免脚本崩掉
三、调用rancli进程的示例
把上面的逻辑套到rancli上就行,只需要改启动命令和对应的提示符(比如假设rancli的提示符是RANCLI>):
def automate_rancli(): os.chdir("/opt/cdma-msc/") rancli_child = pexpect.spawn("./rancli") try: # 等待rancli的提示符,根据实际情况修改 rancli_child.expect("RANCLI>", timeout=10) # 发送你需要的命令,比如查看状态 rancli_child.sendline("show status") rancli_child.expect("RANCLI>", timeout=10) print("=== RANCLI输出结果 ===") print(rancli_child.before.decode("utf-8")) rancli_child.sendline("exit") rancli_child.wait() except pexpect.TIMEOUT: print("RANCLI等待超时") rancli_child.close() except pexpect.EOF: print("RANCLI意外退出") if __name__ == "__main__": automate_rancli()
一些额外提示
- 如果遇到乱码,把
decode("utf-8")改成你系统对应的编码,比如gbk - 超时时间可以根据命令实际执行速度调整,比如复杂命令设成30秒
- 如果需要输入密码这类多步骤交互,用
expect匹配多个模式就行,比如child.expect(["Password:", "RAN>"]),然后判断匹配到的是哪个再处理
内容的提问来源于stack exchange,提问作者Weiqi
相关产品推荐
相关产品推荐

