Linux 我如何将最初的输入导入到随后将是交互式的流程中?
我希望能够将初始命令注入到交互式进程的启动中,以便可以执行以下操作:Linux 我如何将最初的输入导入到随后将是交互式的流程中?,linux,unix,pipe,Linux,Unix,Pipe,我希望能够将初始命令注入到交互式进程的启动中,以便可以执行以下操作: echo "initial command" | INSERT_MAGIC_HERE some_tool tool> initial command [result of initial command] tool> [now I type an interactive command] 什么不起作用: 仅在中管道化初始命令不起作用,因为这会导致stdin未连接到终端 写入/dev/pts/[numb
echo "initial command" | INSERT_MAGIC_HERE some_tool
tool> initial command
[result of initial command]
tool> [now I type an interactive command]
什么不起作用:
- 仅在中管道化初始命令不起作用,因为这会导致stdin未连接到终端
- 写入/dev/pts/[number]会将输出发送到终端,而不是像从终端发送一样将输入发送到进程
- 生成一个命令,该命令分叉子对象,写入其stdin,然后转发来自其自身stdin的所有内容。缺点-终端控制的东西(如线对字符模式)将无法工作。也许我可以用伪终端代理做点什么
- 使用命令行选项修改xterm版本(无论如何,我将为此任务启动一个),以便在遇到所需的提示字符串后插入其他命令。丑陋的
- 制作一个我试图运行的工具的修改版本,以便它接受命令行上的初始命令。破坏了标准安装
abd
。例如。像这样(使用bc
做一个简单的计算作为示例)
[axe@gromp~]$bc结束
7.
此后,
bc
会话保持打开状态,因此在开始标记和结束标记之间提供了什么(在“之间您不需要编写新的工具来转发stdin
)-已经编写了一个(cat
):
这样做的缺点是将管道连接到某个工具,而不是终端。公认的答案很简单,基本上是好的 但它也有一个缺点:程序的输入是管道,而不是终端。这意味着自动完成将不起作用。在很多情况下,这也会禁用漂亮的输出,我听说如果stdin不是终端,有些程序就拒绝工作 下面的程序解决了这个问题。它创建了一个伪终端, 生成一个连接到此伪终端的程序。它首先馈送 额外的输入通过命令行传递,然后提供给它给定的输入 由用户通过标准输入 例如,
ptyppe“import this”python3
使Python首先执行“import this”,然后将您放到交互式命令提示符下,使用
工作完成和其他东西
类似地,ptype“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()
(注意:恐怕此解决方案包含一个可能的死锁。您可能希望以小块的形式提供额外的\u输入以避免死锁)使用“expect”程序很容易做到这一点,该程序旨在让您编写与程序交互的脚本 我编写了一个expect脚本bc.exp来启动计算器“bc”,并向它发送命令“obase=16”,将其置于十六进制输出模式,然后将控制权移交给我 脚本(在名为bc.exp的文件中)为 一个是用
expect bc.exp
@caf的答案是可靠的 我想我会在这里用一个适合我的相关选项来扩展它 我的
实际上是一个命令列表,可以在文本文件中找到。因此,我想通过管道将其传输到
和连接到stdin
cat
处理得非常好,它接受-
读取stdin
:
cat init_file - | some_command
这与cafs答案中讨论的限制相同。这似乎与管道没有任何不同的结果,即此后命令没有交互。我怀疑这只是一种将某些内容输入管道的方便方式。听到这一点很难过。
adb
本身不是某种可以查看的脚本吗?并且没有保留工具交互之后,我假设?adb是一个C程序,我有它的源代码,但我想找到一个通用的解决方案,而不是重新编译每个工具,在那里它将能够做到这一点。类似地,它可能是带外终端控制的一个瓶颈,所以fork&exec’t它从一些代理文件描述符的东西不要太难,但这仍然不是一个通用的解决方案。adb
是否有类似于-i
,-c
的选项,如以下命令:python-i-c'print“initial command”
?这里的初始命令是print“initial command”"
和-i
选项会在之后强制使用交互模式。我编写了一个程序,创建一个管道、分叉、dup2,将它自己的stdin置于原始模式,通过fifo推送一个初始字符串,然后通过代理stdin。在这种情况下似乎可以工作,但仍然不知道是否有标准解决方案。好主意。我已经想知道类似的事情。这确实有效,但没有终端有时也有缺点,例如无法通过链发送ctrl-C(例如,杀死从某个工具获得的嵌入式设备外壳下运行的某些东西),或者进行逐字符访问(我惊讶地发现我可以痛苦地运行我的实验程序中的vi)。不过,这个答案有真正的实用性,因为它是便携式的,不需要任何定制,并且足够长的时间。这个对你的答案的轻微修改似乎达到了我的目的:stty raw-echo;(echo“initial command”和&cat)|一些工具;每一个有用的答案都是正确的。这可以扩展到交互式程序中的多个提示的参数吗?例如,一个有三个问题的程序,总是回答“n”、“y”和“7”?@susjoh:(printf“n\ny
spawn bc
send "obase=16\n"
interact {
\003 exit
}
expect bc.exp
cat init_file - | some_command