Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 我如何将最初的输入导入到随后将是交互式的流程中?_Linux_Unix_Pipe - Fatal编程技术网

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版本(无论如何,我将为此任务启动一个),以便在遇到所需的提示字符串后插入其他命令。丑陋的

  • 制作一个我试图运行的工具的修改版本,以便它接受命令行上的初始命令。破坏了标准安装

(顺便提一句,当前感兴趣的工具是android的adb外壳-我想在手机上打开一个交互式外壳,自动运行命令,然后进行交互式会话)

也许你可以使用它将输入传递到
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