等待 shell 脚本中的密钥可能会通过管道传输到 /bin/bash

等待 shell 脚本中的密钥可能会通过管道传输到 /bin/bash

考虑以下 shell 脚本

echo foo; read; echo bar

运行bash my_script输出“foo”,等待返回键并输出“bar”。

虽然以这种方式运行它可以很好地工作,但如果通过管道传输到 /bin/bash ,它就不再工作了:

$ echo 'echo foo;read;echo bar'|bash

直接输出“foo”和“bar”,无需等待按键。

为什么这样使用时不再起作用?

有没有办法以文件脚本文件以及通过管道传输到 /bin/bash 的脚本字符串的方式重写脚本?

答案1

实际上,这非常简单,首先,您需要在一些记住的描述符中保留您的标准输入:

exec 9<&0

那里。你已经复印了一份。现在,让我们在 shell 中通过管道传输命令。

echo 'echo foo; read <&9; echo bar' | bash

...嗯,这很简单。当然,我们还没有真正完成。我们应该清理一下。

exec 9<&-

好的,现在我们完成了。

但如果我们稍微对命令进行分组,我们就可以避免清理......

{ echo 'echo foo; read <&9; echo bar' | bash; } 9<&0

在这种情况下,描述符仅在其分配的复合命令有效时才有效。

答案2

bash 内置命令read从标准输入 (fd0) 读取数据,但它无法打开标准输入,因为 bash 命令本身已经消耗了标准输入。

你可以eval管什么

eval 'echo foo;read;echo bar'

是:我想不出另一种方法来通过管道传输本身需要从标准输入读取的 shell 脚本。当您通过管道进入 shell 时,该 shell 不是交互式的。

我从来不知道如何复制标准输入文件描述符。请参阅麦克对此的回答。

顺便说一句:你可以看到读取时发生了什么

echo 'echo foo;read;echo bar'|strace bash

答案3

ikrabbe 的回答正确地指出了为什么你的命令行不能按你期望的方式工作。为一个命令行调用新 shell 的常规方法是:

$ sh -c 'echo foo; read; echo bar'

当然,bash如果需要,您可以使用,但是您想要在一行 shell 脚本中执行的操作 98% 都可以在普通的旧 shell 中完成。 (请注意“plain old shell”是缩写词“POS”。)

如果您的目标是让单行 shell 脚本暂停,等待用户输入(可能只是确认/确认),那么这可能就是您应该做的。如果您的目标是更好地了解 shell 的工作原理,请尝试以下操作:

$(echo 'echo foo; read; echo "$REPLY bar"'; echo candy) | $(echo 'echo foo; read; echo "$REPLY bar"'; echo candy) |嘘
糖果条                               (无需等待)
$

相关内容