4

I have a script (that I cannot modify) that I must run regularly that has the following construct:

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

I want to wrap this script such that I always send a "y" character to it. I've tried running the script with the standard tricks for sending a yes:

echo y | '/bin/bash /path/to/script'

and

yes | ./myscript

and

printf "y\n" | ./myscript

and

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

None of these work. I also tried expect.

It's not clear if Mac OS X's built-in expect is working; with expect diagnostic information enabled, expect is properly detecting to the prompt and responding, but the script then terminates.

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

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

Also, to clarify, this is on Mac OS X Monterey.

I'd appreciate any help. Again, I cannot modify the original script.

starball
  • 20,030
  • 7
  • 43
  • 238
efitz
  • 43
  • 7
  • You can always take a look at [`expect`](https://core.tcl-lang.org/expect/index) – Andreas Louv Jan 25 '22 at 13:53
  • if you only want to continuously send a character sequence, you can also use `yes` (by default it sends the character y, but you can also specify another message). You can call it like so : `yes | script.sh` – Aserre Jan 25 '22 at 14:07
  • Does this answer your question? [How do I script a "yes" response for installing programs?](https://stackoverflow.com/questions/7642674/how-do-i-script-a-yes-response-for-installing-programs) – Aserre Jan 25 '22 at 14:08
  • 2
    Those suggestions only work for something which is reading standard input, which by definition is not the case here. – tripleee Jan 25 '22 at 16:52
  • https://stackoverflow.com/questions/32910661/pretend-to-be-a-tty-in-bash-for-any-command and the linked questions appear helpful but not decisively a working solution. I tried the `socat` one but I couldn't pull it off, but probably I didn't understand what I was doing. Probably `expect` at least could solve this. – tripleee Jan 25 '22 at 17:10

2 Answers2

3

You can use socat to fake a new pseudo terminal for a child process.

Let tty.sh be the following script:

#! /bin/bash

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

Then you can connect stdin to the new pty of the child process this way:

echo y | socat stdio exec:./tty.sh,pty,setsid,echo=0
ceving
  • 21,900
  • 13
  • 104
  • 178
  • That looks promising, but is there reason to think that MacOS provides `socat` by default? If not, then step 0 would be "install socat". – John Bollinger Jan 25 '22 at 19:03
  • Thanks ceving, this is definitely the right approach and is working better than the other approaches. I think the script I'm trying to automate is spawning more child shells; I need to figure it out. BTW socat is available for macOS on Homebrew via "brew install socat". – efitz Jan 26 '22 at 00:06
1

You could try to use autoexpect to generate the wrapper (autoscript) script for you:

autoexpect -f autoscript ./myscript.sh
phranz
  • 71
  • 5
  • If it were viable at all, `expect` would be way overkill for this. All of the things the OP describes already trying would then have worked, too. The problem here is that the script being wrapped reads directly from the terminal, as opposed to from the script's standard input. Expect does not interpose itself between the script and its associated terminal. – John Bollinger Jan 25 '22 at 19:12