如何将字符串推送到标准?启动时通过 stdin 提供输入,然后以交互方式读取 stdin 输入



有没有办法在调用程序时将字符串"推送"到程序的 stdin 流?

这样我们就会有

echo "something" | ./my_program

my_program不是在"something"后读取EOF,而是从原始标准输入(例如键盘(读取其进一步的输入。

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

这可能有效:

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

它创建了一个子外壳,其中第一行输出来自echo,其余来自标准输入到 cat ,这是终端(或脚本的标准输入,无论如何(。 我使用-来强调cat需要从标准输入中读取 - 这不仅仅是因为我忘记在cat命令后指定"$@"或其他内容。 省略-不会对操作产生影响;它可能会产生可理解性差异。

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

期望

如果这不能完成工作,那么您可能需要改用expect。 这是一个通用工具,用于编写与其他程序交互的脚本,它使用伪 ttys (ptys( 使其看起来好像终端上的用户正在与其他程序通信。正如 anishsane 所指出的,expect有一个interact命令,可用于让用户在某个固定的序言之后键入程序。

小心

将其适应第二种情况并不是一种舒适的体验:

(echo date; cat -) | bash -i

-i告诉Bash这是一个交互式外壳。 date工作了,之后我收到了提示,但我没有再执行任何命令。 中断给了我更多的提示;几乎所有其他事情似乎都被忽略了。 这可能是cat对其输出进行过多缓冲。

我最终从另一个终端窗口杀死了那个外壳。 我运气更好:

(echo date; cat -) | bash

但是没有来自Bash的提示。 小心;确保你知道如何摆脱麻烦。

I/O 重定向特技

Rici还指出,在这种特殊情况下,您可以使用:

{ { 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 实例不会从执行启动命令的实例继承其状态

您可以通过-a传递给 bash 部分解决此限制,然后导致自动导出由启动命令修改或创建的所有变量

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

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

注意:

  • 这些变量实际上成为环境变量,这意味着由保持打开的 shell 创建的任何子进程也会看到它们。

最新更新