假设您想要一个程序来摄取字符串,然后stdin
在完成后重新附加。
我知道可以通过以下技巧来做到这一点:
(echo id; cat) | sh
效果很好。它不会关闭,stdin
因为它被 所使用cat
。但输出很乱。
深入挖掘后我发现它缺少tty
.
如果我的理解是正确的,sh
在管道中并没有打开tty
.
我发现的技巧是使用expect
.
只需将其放入文件中:
spawn sh
reattach
然后当cat
你重新获得控制权时,执行以下操作:
expect exp.sh
这很好,因为它让我tty
可以做我需要的一切:ssh
,tmux
等等......
我唯一不明白为什么是我看到我输入的所有内容,回到我的终端。
例子:
(echo whoami; cat) | sh
moon
expect exp.sh
spawn sh
sh-3.2$ whoami
whoami
moon
请注意whoami
最后一行登录之前的输出。
有人可以向我解释为什么吗?它显然不是stdout
from的属性,cat
因为它直接附加到sh
- 是的,即使它很愚蠢我尝试了以下操作:(echo id; cat > /dev/null) | sh
然后什么也没有发生。
那么不显示从键盘输入的内容是tty
/的属性吗?pty
答案1
{ echo 'exec <&3 3<&-; id' | sh -si; } 3<&0
似乎适用于大多数sh
实现。我们要求一个交互式 shell -i
(否则,某些 shell 会因为 stdin 不是终端设备而禁用它),从 shell 的 stdin 作为管道开始,然后指示exec <&3
它将其更改为原始(外部)我们之前用 .stdin 保存在文件描述符 3 上3<&0
。
我们这样做前正在运行id
但仍然使用相同的命令线,以便标准输入id
也被恢复。这并不重要,因为id
它不读取其标准输入,但它将是交互式命令,例如编辑器或 shell。
至于为什么会看到你输入的内容(echo id | cat) | sh
。看起来您的实现sh
似乎是一个非常旧的版本,bash
正在交互模式下运行。您可以看到它发出提示,就像-i
使用过一样。
然后它确实实现了自己的行编辑器,但无法禁用 tty 设备自己的行编辑器(因为它的标准输入是管道而不是 tty 设备),因此您可以通过 tty 设备行规则获得您键入的内容的回显,并且一旦您按 Enter 键,cat
就会立即看到该行缓冲区的所有内容,包括立即从管道写入的尾随换行符bash
,并将bash
其输出echo
作为其自己的行编辑器的一部分。
我怀疑如果你这样做:
stty -icanon -echo; (echo id; cat) | sh; stty sane
您会得到更好的行为,并且可能能够使用 readline 行编辑功能,因为bash
它们会直接接收您输入的每个字符。
有关在用户接管交互式 shell 之前自动运行命令的其他选项,请参阅: