9

So I have a program (say, programA), that will give me an output, for example: yes, no, maybe, probably, possibly, impossible, banana.

I want to make a script that will do something, whatever it is, based on that output. Let's say I only need to account for yes, maybe and banana.

So far what I would do, is use case like so:

case $program_output in
  yes) echo "good word: $program_output" ;;
  maybe) echo "good word: $program_output" ;;
  banana) echo "good word: $program_output" ;;
  *) echo "bad word: $program_output" ;;
esac

But recently I was fiddling with the if statement, and found out I can do this faster like so:

if [[ "yesmaybebanana" =~ ${program_output} ]]; then
  echo "good word: ${program_output}"; else echo "bad word: ${program_output}";
fi

Is there any reason why I should not use the if statement for this? This is a case where $program_output cannot have spaces in it, and it's a limited list of words it can output.

0

3 Answers 3

19

If you want to use bash's regular expression functions (which however are bash-specific and therefore not portable), you should at least use the proper "OR"-type operator to enforce exact match with one of the allowed words, as in

if [[ $program_output =~ ^(yes|maybe|banana)$ ]]
then
    echo "Good word: $program_output"
else
    echo "Bad word: $program_output"
fi

Notice that there must be no quotes around the regular expression, and that the word alternatives are enclosed between ^ and $ anchors to ensure that no sub-string can trigger a match (such as yessir which would otherwise be caught by the pattern yes).

18

The if version is not going to be as reliable as case here because it will catch all substrings of yesmaybebanana - it will match for b, bebana etc:

#!/usr/bin/env bash

program_output='bebana'

if [[ "yesmaybebanana" =~ ${program_output} ]]; then echo "good word: ${program_output}"; else echo "bad word: ${program_output}"; fi

Output:

good word: bebana

And it's not portable - try running it with dash:

$ dash ./a.sh
./a.sh: 6: ./a.sh: [[: not found
bad word: bebana

You can significantly simplify your case version by using multiple words in a single line:

case $program_output in
  yes | maybe | banana) echo "good word: $program_output" ;;
  *) echo "bad word: $program_output" ;;
esac
1
  • 1
    "because it will catch all substrings of yesmaybebanana" -- as well as all matching regular expressions. If program_output is ., .*, beba(na){2}, (foo bar)?, etc. those would also be interpreted as good words.
    – JoL
    Apr 30, 2020 at 21:37
13

bash's extended patterns also work here:

if [[ $program_output == @(yes|maybe|banana) ]]
then
    echo "program output is one of yes, maybe, banana"
fi

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.