在非交互式shell会话中运行多个命令并解析输出

时间:2016-03-07 17:01:12

标签: bash shell ssh non-interactive

我想通过stdin / stdout与(远程)非交互式shell进行通信,以运行多个命令并读取输出。问题是如果我在shell stdin上填充多个命令,我就无法检测到各个命令的输出之间的界限。

类似Python的伪代码:

Observable

但显然sh = Popen(['ssh', 'user@remote', '/bin/bash'], stdin=PIPE, stdout=PIPE) sh.stdin.write('ls /\n') sh.stdin.write('ls /usr\n') sh.stdin.close() out = sh.stdout.read() 包含两个连接命令的输出,我无法可靠地拆分它们。

到目前为止,我最好的想法是在输出之间插入out个字节:

\0

然后我可以将sh.stdin.write('ls /; echo -ne "\0"\n') sh.stdin.write('ls /usr; echo -ne "\0"\n') 分成零个字符。

其他不适合我的方法:

  • 我不想为每个命令运行一个单独的ssh会话,因为握手太重了。
  • 我不希望在创建的shell上强制使用ControlMaster选项来尊重最终用户的ssh_config。
  • 我不希望要求用户安装特定的服务器程序。

有没有更好的方法在一个会话中运行多个命令并获得单独的输出?是否有广泛部署的shell具有某种二进制输出模式?

PS。有一个重复的问题,但它没有一个令人满意的答案: Run multiple commands in a single ssh session using popen and save the output in separate files

1 个答案:

答案 0 :(得分:1)

对于SSH,我使用了paramiko及其invoke_shell方法来创建一个可编程管理的shell实例。

以下不是一个完整的答案,它仍然是hacky,但我觉得这是朝着正确方向迈出的一步。

我在Windows中需要相同的读/写shell实例功能,但没有运气,所以我稍微扩展了你的方法(顺便说一句,谢谢你的想法)。

我通过在每个命令之间放置一个条件退出来验证每个命令是否基于其退出代码成功执行,然后我使用所述条件检查的文本(已知字符串)作为定界符来定义每个命令的响应。

一个粗略的例子:

from subprocess import Popen, PIPE

sh = Popen('cmd', stdin=PIPE, stdout=PIPE)
sh.stdin.write(b'F:\r\n')
sh.stdin.write(b"if not %errorlevel% == 0 exit\r\n")
sh.stdin.write(b'cd F:\\NewFolder\r\n')
sh.stdin.write(b"if not %errorlevel% == 0 exit\r\n")
sh.stdin.write('...some useful command with the current directory confirmed as set to F:\NewFolder...')
sh.stdin.close()
out = sh.stdout.read()
sh.stdout.close()
# Split 'out' by each line that ends with 'if not %errorlevel% == 0 exit' and do what you require with the responses