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?

  • Possible duplicate of Prepare answers for questions of a command – Christopher Nov 1 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. – guillermo chamorro Nov 1 at 14:43
  • @guillermochamorro Thanks, this works, but I would have to change any statement :) – chefarov Nov 1 at 14:52
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
  • +1 very clever idea – Jesse_b Nov 1 at 14:44
  • Nice trick, thank you – chefarov Nov 1 at 14:50
  • 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 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 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 at 9:15
9

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.

  • 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 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. – steeldriver Nov 1 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 at 8:11
  • 1
    Uh, any reason you didnt cat your sample script? Surprised to see a grep there – D. Ben Knoble Nov 3 at 1:09
5

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
  • 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. – roaima Nov 2 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 at 10:02
  • Nice one, thanks! – chefarov Nov 4 at 8:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.