我希望能够在启动交互式进程时注入初始命令,以便我可以执行以下操作:
echo "initial command" | INSERT_MAGIC_HERE some_tool
tool> initial command
[result of initial command]
tool> [now I type an interactive command]
Run Code Online (Sandbox Code Playgroud)
什么行不通:
只是管道输入初始命令不起作用,因为这导致stdin没有连接到终端
写入/ dev/pts/[number]将输出发送到终端,而不是输入到进程,就像它来自终端一样
什么会有缺点:
创建一个分叉子命令,写入stdin,然后从自己的stdin转发所有内容.下行 - 终端控制事物(如线与字符模式)不起作用.也许我可以用代理伪终端做些什么?
使用命令行选项创建xterm的修改版本(我正在为此任务启动一个),以在遇到所需的提示字符串后注入其他命令.丑陋.
制作我正在尝试运行的工具的修改版本,以便它在命令行上接受初始命令.打破标准安装.
(顺便提一下,当前感兴趣的工具是android的adb shell - 我想在手机上打开一个交互式shell,自动运行命令,然后进行交互式会话)
caf*_*caf 38
你不需要编写一个新工具来转发stdin- 一个已经写好了(cat):
(echo "initial command" && cat) | some_tool
Run Code Online (Sandbox Code Playgroud)
这确实有连接管道的缺点some_tool,而不是终端.
接受的答案很简单,而且大多数都很好.
但它有一个缺点:程序将管道作为输入,而不是终端.这意味着自动完成功能不起作用.在很多情况下,这也会禁用漂亮的输出,我听说如果stdin不是终端,一些程序就会拒绝工作.
以下程序解决了这个问题.它创建一个伪终端,产生一个连接到这个伪终端的程序.它首先提供通过命令行传递的额外输入,然后通过stdin提供用户给出的输入.
例如,ptypipe "import this" python3让Python首先执行"import this",然后它将你带到交互式命令提示符,工作完成和其他东西.
同样,ptypipe "date" bash运行Bash,执行date然后给你一个shell.再次,工作完成,着色提示等.
#!/usr/bin/env python3
import sys
import os
import pty
import tty
import select
import subprocess
STDIN_FILENO = 0
STDOUT_FILENO = 1
STDERR_FILENO = 2
def _writen(fd, data):
while data:
n = os.write(fd, data)
data = data[n:]
def main_loop(master_fd, extra_input):
fds = [master_fd, STDIN_FILENO]
_writen(master_fd, extra_input)
while True:
rfds, _, _ = select.select(fds, [], [])
if master_fd in rfds:
data = os.read(master_fd, 1024)
if not data:
fds.remove(master_fd)
else:
os.write(STDOUT_FILENO, data)
if STDIN_FILENO in rfds:
data = os.read(STDIN_FILENO, 1024)
if not data:
fds.remove(STDIN_FILENO)
else:
_writen(master_fd, data)
def main():
extra_input = sys.argv[1]
interactive_command = sys.argv[2]
if hasattr(os, "fsencode"):
# convert them back to bytes
# http://bugs.python.org/issue8776
interactive_command = os.fsencode(interactive_command)
extra_input = os.fsencode(extra_input)
# add implicit newline
if extra_input and extra_input[-1] != b'\n':
extra_input += b'\n'
# replace LF with CR (shells like CR for some reason)
extra_input = extra_input.replace(b'\n', b'\r')
pid, master_fd = pty.fork()
if pid == 0:
os.execlp("sh", "/bin/sh", "-c", interactive_command)
try:
mode = tty.tcgetattr(STDIN_FILENO)
tty.setraw(STDIN_FILENO)
restore = True
except tty.error: # This is the same as termios.error
restore = False
try:
main_loop(master_fd, extra_input)
except OSError:
if restore:
tty.tcsetattr(0, tty.TCSAFLUSH, mode)
os.close(master_fd)
return os.waitpid(pid, 0)[1]
if __name__ == "__main__":
main()
Run Code Online (Sandbox Code Playgroud)
(注意:我担心此解决方案可能存在死锁.您可能希望以小块的形式提供extra_input以避免它)
| 归档时间: |
|
| 查看次数: |
19910 次 |
| 最近记录: |