如何将string推送到stdin? 在启动时通过stdin提供input,然后交互地读取stdininput

调用它时,有没有办法将一个string“推”到程序的标准inputstream?

所以我们会有效果的

echo "something" | ./my_program 

但不是在"something"之后读取EOF, my_program会从原始标准input(例如键盘)读取其进一步的input。

例如:假设我们想要启动一个bash shell,但是我们想要做的第一件事就是调用dateecho date | bash echo date | bash不会做这个工作,因为shell会在运行date之后终止。

这可能工作:

 (echo "something"; cat -) | ./my_program 

它创建了一个子shell,其中第一行输出来自echo ,其余的来自标准输入cat ,它是终端(或脚本的标准输入,无论如何)。 我使用-来强调cat需要从标准输入中读取 – 不是简单地说我忘记了在cat命令之后指定"$@"或什么的。 省略-不会产生运营差异; 这可能会造成可理解性差异。

请注意, my_program的输入不再是终端,而是连接到终端的管道,这会影响程序的行为。 cat过程也引入了延迟。

期望

如果这样做不能完成这项工作,那么你可能需要使用expect来代替。 这是一个用于脚本与其他程序交互的通用工具,它使用伪ttys(ptys)使其看起来好像终端上的用户正在与另一个程序进行通信。 正如anishsane所 指出的那样 , expect有一个interact命令,可以让用户在输入一些固定的序言之后输入程序。

谨防

适应这个你的第二个场景并不是一个舒适的体验:

 (echo date; cat -) | bash -i 

-i告诉Bash这是一个交互式shell。 date工作,我得到一个提示后,但我没有得到任何更多的命令执行。 中断让我更多的提示; 几乎一切似乎都被忽略了。 这可能是cat做了太多的缓冲输出。

我终于从另一个终端窗口中杀死了这个shell。 我有更好的运气:

 (echo date; cat -) | bash 

但Bash没有提示。 小心; 确保你知道如何摆脱困境。

I / O重定向特技

里奇也指出 ,在这个特殊情况下,你可以使用:

 { { echo date; echo 'exec 0<&3-';} | bash -i; } 3<&0 

这是相当聪明的,因为结尾3<&0在描述符3上复制了原始标准输入(文件描述符0),然后运行bash -i ,输入来自两个echo语句。 第一个请求日期。 第二个重定向的东西,使标准输入现在来自文件描述符3(这是0<&3部分) – 这是原来的标准输入,也就是“终端” – 也关闭文件描述符3(这是尾随- ;它是通过POSIX shell I / O重定向的Bash扩展)。

作为乔纳森·莱弗勒(Jonathan Leffler)的一个可能更简单但有限选择 的有用答案的补充:

如果

  • ./my_programbash ,就像在OP的例子中一样
  • 并且启动命令产生的副作用是可以接受的:
    • 无论如何:在所有保持打开bash实例中都不可见
    • OR:限于将所有修改后的变量作为导出变量继承

你可以尝试下面的方法:

 bash -c "$(<command that produces Bash commands>); exec bash -i" 

使用date命令的例子作为启动命令:

 bash -c "$(echo 'date'); exec bash -i" 

这个执行date ,然后用一个新的实例替换正在运行的bash实例,然后保持打开 (由于既没有接收stdin输入,也没有通过-c传递给它的命令)。

为了说明对启动 shell环境所做的任何更改都不会传播到最终保持打开状态的环境 ,请考虑以下事项:

 bash -c "$(echo 'date; foo=bar; echo $foo'); exec bash -i" 

这将打印日期并分配和打印变量$foo ,但是如果您再次执行echo $foo ,则不会定义它,因为最终保持打开状态的shell实例不会从执行启动命令的状态继承它的状态

你可以通过传递-abash部分解决这个限制 ,这会导致所有由启动命令修改或创建的变量自动导出

 bash -ac "$(echo 'date; foo=bar; echo $foo'); exec bash -i" 

现在,如果在保持打开的实例中再次执行echo $foo ,它将会打印bar

注意:

  • 这样的变量实际上变成了环境变量,这意味着由开放式shell创建的任何子进程也能看到它们。