Linux 如何将初始输入通过管道传输到流程中,然后进行交互?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5843741/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I pipe initial input into process which will then be interactive?
提问by Chris Stratton
I'd like to be able to inject an initial command into the launching of an interactive process, so that I can do something like this:
我希望能够将初始命令注入到交互式进程的启动中,以便我可以执行以下操作:
echo "initial command" | INSERT_MAGIC_HERE some_tool
tool> initial command
[result of initial command]
tool> [now I type an interactive command]
What doesn't work:
什么不起作用:
Just piping the initial command in doesn't work, as this results in stdin not being connected to the terminal
Writing to /dev/pts/[number] sends the output to the terminal, not input to the process as if it were from the terminal
仅仅输入初始命令是行不通的,因为这会导致 stdin 没有连接到终端
写入 /dev/pts/[number] 将输出发送到终端,而不是像从终端一样输入到进程
What would but with disadvantages:
什么会但有缺点:
Make a command which forks a child, writes to its stdin and then forwards everything from its own stdin. Downside - terminal control things (like line vs character mode) won't work. Maybe I could do something with proxying of pseudo terminals?
Make a modified version of xterm (I'm launching one for this task anyway) with a command line option to inject additional commands after encountering a desired prompt string. Ugly.
Make a modified version of the tool I'm trying to run so that it accepts an initial command on the command line. Breaks the standard installation.
创建一个命令,它分叉一个孩子,写入它的标准输入,然后从它自己的标准输入转发所有内容。缺点 - 终端控制(如行与字符模式)将不起作用。也许我可以通过代理伪终端来做些什么?
使用命令行选项制作 xterm 的修改版本(无论如何,我正在为此任务启动一个),以在遇到所需的提示字符串后注入其他命令。丑陋的。
制作我尝试运行的工具的修改版本,以便它接受命令行上的初始命令。打破标准安装。
(The tool of current interest, incidentally, is android's adb shell - I want to open an interactive shell on the phone, run a command automatically, and then have an interactive session)
(目前感兴趣的工具,顺便说一句,是android的adb shell——我想在手机上打开一个交互式shell,自动运行一个命令,然后进行一个交互式会话)
采纳答案by caf
You don't need to write a new tool to forward stdin
- one has already been written (cat
):
您不需要编写新的工具来转发stdin
- 已经编写了一个 ( cat
):
(echo "initial command" && cat) | some_tool
This does have the downside of connecting a pipe to some_tool
, not a terminal.
这确实有将管道连接到some_tool
而不是终端的缺点。
回答by Axel Knauf
Maybe you could use a here documentto pass your input to abd
. E. g. like this (using bc
to do a simple calculation as example).
也许您可以使用此处的文档将您的输入传递给abd
. 例如 像这样(bc
以做一个简单的计算为例)。
[axe@gromp ~]$ bc <<END
> 3 + 4
> END
7
The bc
session remains open afterwards, so what is provided between the start and end markers (between "<<END" and "END") will be passed to the command.
该bc
会话保持打开之后,所以开始和结束标记之间的内容(“<< END”和“结束”之间)将被传递给命令。
回答by WGH
The accepted answer is simple and mostly good.
接受的答案很简单,而且大多很好。
But it has a disadvantage: the programs gets a pipe as its input, not a terminal. This means that autocompletion will not work. In a lot of cases, this also disables pretty output, and I've heard some programs just refuse to work if stdin is not a terminal.
但它有一个缺点:程序以管道作为输入,而不是终端。这意味着自动完成将不起作用。在很多情况下,这也会禁用漂亮的输出,而且我听说如果 stdin 不是终端,一些程序只是拒绝工作。
The following program solves the problem. It creates a pseudoterminal, spawns a program connected to this pseudoterminal. It first feeds extra input passed via commandline, and then feeds it input given by user via stdin.
下面的程序解决了这个问题。它创建一个伪终端,生成一个连接到这个伪终端的程序。它首先提供通过命令行传递的额外输入,然后提供用户通过标准输入提供的输入。
For example, ptypipe "import this" python3
makes Python execute "import this" first, and then it drops you to interactive command prompt, with
working completion and other stuff.
例如,ptypipe "import this" python3
让 Python 首先执行“import this”,然后它会让你进入交互式命令提示符,完成工作和其他东西。
Likewise, ptypipe "date" bash
runs Bash, which executes date
and then gives a shell to you. Again, with working completion, colourized prompt and so on.
同样,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()
(Note: I'm afraid this solution contains a possible deadlock. You may want to feed extra_input in small chunks to avoid it)
(注意:恐怕这个解决方案包含一个可能的死锁。您可能希望以小块形式提供 extra_input 以避免它)
回答by Larry Stewart
This is easy to do with the program "expect" which is intended to let you write scripts to interact with programs.
使用“expect”程序很容易做到这一点,该程序旨在让您编写脚本与程序进行交互。
I tested this by writing an expect script bc.exp to launch the calculator "bc" and send it the command "obase=16" to put it into hexadecimal output mode, and then turn over control to me.
我通过编写一个期望脚本 bc.exp 来启动计算器“bc”并向它发送命令“obase=16”以将其置于十六进制输出模式,然后将控制权交给我来测试这一点。
The script (in a file named bc.exp) is
脚本(在名为 bc.exp 的文件中)是
spawn bc
send "obase=16\n"
interact {
expect bc.exp
3 exit
}
One runs it with
一个运行它
##代码##