1

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

在类似 Python 的伪代码中:

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

然后我可以拆分out零个字符。

其他对我不起作用的方法:

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

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

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

4

1 回答 1

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
于 2016-08-31T10:20:02.883 回答