我如何自动化一个从/dev/tty读取的bash脚本?

5

我有一个脚本(无法修改),需要定期运行,其结构如下:

read -r response < /dev/tty
if [ "$response" = 'y' ]; then
...

我想包装这个脚本,以便我总是向其发送一个 "y" 字符。我尝试使用发送 yes 的标准技巧来运行脚本:
echo y | '/bin/bash /path/to/script'

并且

yes | ./myscript

并且

printf "y\n" | ./myscript

/bin/bash /path/to/script < /path/to/y-file

这些方法都没有生效。我还尝试了expect

目前不清楚Mac OS X内置的expect是否可用;启用expect诊断信息后,expect能够正确地检测到提示符并响应,但脚本随后终止。

#!/bin/bash
set timeout -1
SCRIPT="~/myscript"

expect -d <<EOF
spawn $SCRIPT
expect "prompt string"
send "y\r"
EOF

另外需要澄清的是,这是在 Mac OS X Monterey 上。

非常感谢任何帮助。再次强调,我无法修改原始脚本。


你可以随时查看 expect - Andreas Louv
如果您只想连续发送一个字符序列,也可以使用 yes 命令(默认情况下它会发送字符 y,但您也可以指定其他消息)。您可以这样调用它:yes | script.sh - Aserre
这回答解决了你的问题吗?如何为安装程序编写“是”响应的脚本? - Aserre
2
这些建议仅适用于读取标准输入的情况,而根据定义,这里并非如此。 - tripleee
https://dev59.com/A1wY5IYBdhLWcg3wLFSw 和相关问题似乎有所帮助,但并没有决定性的解决方案。我尝试了 socat 的方法,但是我无法成功执行,可能是因为我不理解我在做什么。也许 expect 至少可以解决这个问题。 - tripleee
2个回答

4
你可以使用 socat 来为子进程创建一个新的伪终端。

假设有以下脚本 tty.sh:

#! /bin/bash

read -r response < /dev/tty
if [ "$response" = 'y' ]; then
  echo yes
else
  echo no
fi

然后,您可以通过以下方式将标准输入连接到子进程的新pty:
echo y | socat stdio exec:./tty.sh,pty,setsid,echo=0

这看起来很有前途,但是有理由认为MacOS默认不提供socat吗?如果没有,那么步骤0就是“安装socat”。 - John Bollinger
谢谢ceving,这绝对是正确的方法,比其他方法更有效。我想我正在尝试自动化的脚本正在生成更多的子shell;我需要找出原因。顺便说一下,macOS上可以通过“brew install socat”在Homebrew中获取socat。 - efitz

1
您可以尝试使用autoexpect为您生成包装器(autoscript)脚本:
autoexpect -f autoscript ./myscript.sh

如果有可能的话,expect 对于这个问题来说就是过度杀伤力了。OP 描述的所有尝试都应该已经起作用了。这里的问题在于被包装的脚本直接从终端读取,而不是从脚本的标准输入读取。Expect 不会介入脚本和其关联终端之间的交互。 - John Bollinger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接