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

How do I push a string to stdin? Provide input via stdin on startup, then read stdin input interactively

有没有办法在调用程序时将字符串 "push" 发送到程序的标准输入流?

这样我们就可以达到

的效果
echo "something" | ./my_program

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

示例: 假设我们要启动一个 bash shell,但我们想在其中做的第一件事是调用 dateecho 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 对其输出缓冲过多。

我最终从另一个终端 window 杀死了那个 shell。我运气更好:

(echo date; cat -) | bash

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

I/O 重定向特技

rici also 在这种特殊情况下,您可以使用:

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

这很聪明,因为尾随的 3<&0 在描述符 3 上复制了原始标准输入(文件描述符 0),然后使用来自两个 [=14] 的输入运行 bash -i =] 语句。第一个请求日期。第二个重新重定向,使标准输入现在来自文件描述符 3(即 0<&3 部分)——这是原始标准输入,又名 'the terminal' ——并关闭文件描述符 3(这是尾随 -;它是 Bash extension over POSIX shell I/O redirection).

可能更简单但有限的替代方案补充

IF

  • ./my_programbash,如 OP 的示例
  • 并且启动命令产生的副作用是可以接受的:
    • EITHER:对 保持打开状态的 bash 实例完全不可见
    • 或:仅限于继承所有修改的变量作为导出的变量

您可以尝试以下方法:

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

date命令作为启动命令为例:

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

执行 date 然后 运行 bash 实例替换为 新实例 实例,然后 保持打开状态 (因为既没有接收标准输入也没有通过 -c 向其传递命令)。

为了说明对 startup 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 创建的任何子进程也能看到它们。