5

I have several user input statements like:

read -r -p "Do u want to include this step (y) or not (n) (y/N)"? answer
if [[ "$answer" =~ ^[Yy]$ ]]; then 
    ...
fi

I am looking for a way to automatically answering yes to all these questions. Imagine a non-interactive session where the user invokes the script with --yes option. No further stdin input.

The only way I can think right now is adding another condition on each if statement.

Any thoughts?

3
  • Possible duplicate of Prepare answers for questions of a command Nov 1, 2019 at 14:22
  • 1
    [[ "$1" = "--yes" ]] && command || read -r -p "Do u want..., something like this will work for you? I ask taking in accout your response to Jesse_b answer. Nov 1, 2019 at 14:43
  • @guillermochamorro Thanks, this works, but I would have to change any statement :)
    – chefarov
    Nov 1, 2019 at 14:52

3 Answers 3

10

If you use read only for these questions, and the variable is always called answer, replace read:

# parse options, set "$yes" to y if --yes is supplied
if [[ $yes = y ]]
then
    read () {
        answer=y
    }
fi
3
  • 3
    That's neat, and possibly confusing for a reader who doesn't know the script. I would suggest at least renaming the function to alleviate that (and to allow using read in the ordinary sense elsewhere in the script, if required).
    – ilkkachu
    Nov 2, 2019 at 8:10
  • 2
    @ilkkachu ah, but that way, OP will have to go about modifying the usages of read, which is something they're looking to avoid. To avoid confusion, maybe logging that the read is being overridden is better. And they can always use builtin read for the ordinary sense.
    – muru
    Nov 2, 2019 at 8:58
  • @muru, sure, but changing the function name is a rather minor modification anyway. It could possibly even be automated with something like sed -e '/read.*answer/s/read/read_or_yes/'
    – ilkkachu
    Nov 2, 2019 at 9:15
10

You could use yes(1), which shouldn't require any modification to your script at all.

$ grep . test.sh
#!/bin/bash
read -rp 'What say you? ' answer
echo "Answer is: $answer"
read -rp 'And again? ' answer2
echo "Answer 2 is: $answer2"
$
$ yes | ./test.sh
Answer is: y
Answer 2 is: y

It will repeat a specified expletive indefinitely, if none is specified it will default y.

7
  • Thank you. Good thought, however, optimally, I would prefer to not change the way the script is been called already: ./test.sh --yes - On the other hand I could use it as a work-around :)
    – chefarov
    Nov 1, 2019 at 14:30
  • 1
    I guess the "trick" version of this one would be to parse options as per the accepted answer, then conditionally exec 0< <(yes) (possibly duplicating the descriptor first so that it can be restored if stdin is needed again later). But it's hacky compared to overloading read. Nov 1, 2019 at 15:29
  • 1
    Upside of piping input from yes: it'll automatically answer "yes" to any commands launched by the shell, too (e.g. cp -i). Downside of using yes: it'll automatically answer "yes" to any commands launched by the shell, too. ;)
    – ilkkachu
    Nov 2, 2019 at 8:11
  • 1
    Uh, any reason you didnt cat your sample script? Surprised to see a grep there Nov 3, 2019 at 1:09
  • Quick and dirty empty line removal? ¯\_(ツ)_/¯
    – B Layer
    Apr 21, 2020 at 15:45
6

I would put the whole decision logic in a function, both checking the auto-mode and possibly querying the user. Then call just that from the main level in each case. want_act below returns truthy/falsy in itself, no need for a string comparison in the main level and it's clear to the reader what the condition does.

#!/bin/bash
[[ $1 = --yes ]] && yes_mode=1

want_act() {
    [[ $yes_mode = 1 ]] && return 0
    read -r -p "Include step '$1' (y/n)? " answer
    [[ $answer = [Yy]* ]] && return 0
    return 1
}

if want_act "frobnicate first farthing"; then
    echo "frobnicating..."
fi
3
  • 2
    From a maintenance perspective this is a better option than overriding read. On the other hand, if that option hadn't already been offered i would have suggested it myself. +1 to you both, I think. Nov 2, 2019 at 9:15
  • Suggestion: like I did, switch the implementation itself based on the option: if [[ $yes_mode = 1 ]]; then want_act() { ...;}; else want_act() { ...;}; fi. The check for the option only needs to be done once, after all.
    – muru
    Nov 2, 2019 at 10:02
  • Nice one, thanks!
    – chefarov
    Nov 4, 2019 at 8:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .