![在不使用 EOF 的情况下自动从 bash 脚本输入文本](https://linux22.com/image/23788/%E5%9C%A8%E4%B8%8D%E4%BD%BF%E7%94%A8%20EOF%20%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E8%87%AA%E5%8A%A8%E4%BB%8E%20bash%20%E8%84%9A%E6%9C%AC%E8%BE%93%E5%85%A5%E6%96%87%E6%9C%AC.png)
我正在运行 Ubuntu Linux。假设有一个程序叫myprogram
.该程序提示用户输入;具体来说,用户必须在出现提示时键入一个整数并按Enter。我想使用 bash 脚本自动执行此过程。特别是,我想执行100 次(使用从 到的myprogram
计数器)。在每次执行 时,我想在出现提示时输入当前值。 i
1
100
myprogram
i
(顺便说一句,myprogram
采用 options/switches -options
,所有这些都将是常量,因此在 bash 脚本中指定。)
该 bash 脚本的不完整骨架可能是:
#!/bin/bash
for i in {1..100}
do
myprogram -options
done
现在我想修改上面的代码,以便i
在程序提示时输入当前值。做这个的最好方式是什么?
我正在使用的软件的网站建议<<EOF
在行尾使用myprogram -options
。我认为这告诉 bash 查看“文件末尾”以供使用的输入。但是如果我不想将输入放在结尾文件的?如果我想将其立即放在<<
or后面怎么办<
?
原因是事情会变得更加复杂。例如,我可能会引入一个j
以某种非线性、非顺序方式变化的整数计数器。然后,我希望在每次迭代时提供j
to的当前值,但在调用和文件末尾之间myprogram
, 的值可能会发生变化。 j
myprogram -options
EOF
你有什么建议吗?
答案1
对于几乎所有程序, 和 都echo $i | myprogram -options
应该myprogram -options <<<$i
工作,通过标准输入提供程序$i
。
<foo
将使用名为 stdin 的文件的内容foo
。
<<foo
将使用该文本与仅由 组成的行之间的文本foo
作为标准输入。这是一个这里的文档(heredoc),正如吉尔斯所说;EOF
实际上并不意味着文件的结尾,它只是一个常见的定界符描述符(在本例中我们使用“foo”代替)。
<<<foo
将使用字符串“foo”作为标准输入。您还可以指定一个变量$foo
,shell 会将其内容用作标准输入,如我上面所示。这被称为此处字符串,因为它使用一个短字符串,而不是整个块,就像在定界文档中一样。 Herestrings 在 bash 中有效,但在/bin/sh
.
答案2
该网站推荐的语法称为这里的文档。文件程序的输入紧接在包含 的行下方开始<<EOF
,并且不会在脚本末尾处终止,而是在包含确切文本的行处终止EOF
(注意不要有多余的空格)。顺便说一句,您可以使用任何不包含任何 shell 特殊字符的结束标记:EOF
不是关键字,它只是传统的。
#!/bin/bash
for i in {1..100}
do
myprogram -options <<EOF
$i
EOF
for j in {1..42}; do
myprogram2 <<EOF
$i
$j
EOF
done
done
答案3
上面凯文和吉尔斯提到的文件或简单的管道在许多情况下都可以使用。
对于更复杂的情况,您可能需要研究 Expect 或类似的模块(例如 Expect::Simple CPAN 模块是一个非常易于使用的 perl 实现)。就我个人而言,我更喜欢 perl 模块(Expect 本身是 tcl),但有许多常见脚本语言的实现。甚至可以写一个非常使用 while 和 read 在 sh 或 bash 中原始实现该想法。
Expect 和类似工具的一般思想是等待程序输出中的指定字符串或模式,然后向其提供您想要的任何输入。
一个常见的示例用途是自动登录,通过“期待”(即等待)字符串“ogin:”,发送登录名,然后期待字符串“word:”并发送密码。
如果您有 myprogram 的源代码,最后一个选择是修改它以获取您想要作为命令行选项提供的输入。这可能需要更多的前期工作,但比乱搞 Expect 或将数据传输到并非设计为以这种方式使用的程序中要简单得多。
...并且不要忘记将您的补丁提交到上游的 myprogram :) 即使他们不喜欢您编码的方式,他们也可能非常喜欢这个想法,可以自己添加该功能。上游开发者倾向于欣赏那些奋力拼搏、做出贡献的人,而不是要求或抱怨的人。