3

I am trying to do something like this to make a script to perform backups if they have failed. I am taking in the environment as argument to the script.

The one thing i am unsure on how to do is that i want to verify $1 to only include some predefined values. The predefined values should be something like tst, prd, qa, rpt. Anyone?

#!/bin/bash
ENVIRONMENT=$1 
BACKUPDATE=$(date +"%d_%m_%Y")
BACKUPFILE="$ENVIRONMENT".backup."$BACKUPDATE".tar.gz

if [ $1 ==  "" ] 
 then
 echo "No environment specified"
 exit
elif [ -f "$BACKUPFILE" ]; then
   echo "The file '$BACKUPFILE' exists."
else
   echo "The file '$BACKUPFILE' in not found."
   exec touch "$BACKUPFILE"
fi
runegjo
  • 31
  • 4
  • One-liner for the first test: `[[ -z "$1" ]] && echo "No environment specified" && exit 1`. And you don't need to `exec touch`. `touch` is enough on its own. – Matthieu Jul 06 '19 at 19:48
  • 2
    @Matthieu Shorter one-liner: `: ${1:?No environment specified}` – chepner Jul 06 '19 at 19:53
  • @chepner I *knew* there was something around, thanks! (Also see https://stackoverflow.com/questions/8889302/what-is-the-meaning-of-a-question-mark-in-bash-variable-parameter-expansion-as-i) – Matthieu Jul 06 '19 at 19:59
  • 1
    `[ "$1" = "" ]`, or just `[ -z "$1" ]`. Always quote your expansions, and don't use `==`; it isn't standardized in [the POSIX specification for `test`](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html). – Charles Duffy Jul 06 '19 at 20:30

2 Answers2

3

You can use case:

case "$1" in
    tst) echo "Backing up Test style" ;;
    prd)
        echo "Production backup"
        /etc/init.d/myservice stop
        tar czf ...
        /etc/init.d/myservice start
        ;;
    qa) echo "Quality skipped" ;;
    rpt)
        echo "Different type of backup"
        echo "This could be another processing"
        ...
        ;;
    *)
        echo "Unknown backup type"
        exit 2
        ;;
esac

Note the double ;; to end each case, and the convenient use of pattern matching.

Edit: following your comment and @CharlesDuffy suggestion, if you want to have all valid options in an array and test your value against any of them (hence having the same piece of code for all valid values), you can use an associative array:

declare -A valids=(["tst"]=1 ["prd"]=1 ["qa"]=1 ["rpt"]=1)
if [[ -z ${valids[$1]} ]] ; then
    echo "Invalid parameter value"
    # Any other processing here ...
    exit 1
fi
# Here your parameter is valid, proceed with processing ...

This works by having a value (here 1 but it could be anything else in that case) assigned to every valid parameter. So any invalid parameter will be null and the -z test will trigger.

Credits go to him.

Matthieu
  • 2,736
  • 4
  • 57
  • 87
  • @runegjo you can edit your question with a list of choices and we'll show you some examples :) Each case expression corresponds to one of the possible choices, and you put the corresponding code between the `)` and the `;;` – Matthieu Jul 06 '19 at 19:56
  • 2
    BTW, note that TLDP, and the ABS in particular, is somewhat notorious for outdated information and examples that showcase bad practices. The [Wooledge BashGuide](http://mywiki.wooledge.org/BashGuide) was written specifically to be a replacement without these faults. There's a reason the ABS isn't listed in the "Books and Resources" section of https://stackoverflow.com/tags/bash/info; please consider linking to the official manual, the [bash-hackers' wiki](https://wiki.bash-hackers.org), or the Guide instead. – Charles Duffy Jul 06 '19 at 20:34
  • @CharlesDuffy, thank you for the valuable info about the source. I edited my answer with a link to bash-hackers' wiki, that I used quite a lot some time ago. – Matthieu Jul 06 '19 at 20:45
  • @runegjo I added Charles Duffy's comment in an edit. See if it works better for you. – Matthieu Jul 06 '19 at 21:49
  • @CharlesDuffy I used your comment to edit my answer. If you at your own answer, I'll rollback that edit. – Matthieu Jul 06 '19 at 21:50
1

Depending on how many different values you have, what about a case statement? It even allows for globbing.

case $1 in
  (John)   printf "Likes Yoko\n";;
  (Paul)   printf "Likes to write songs\n";;
  (George) printf "Harrison\n";;
  (Ringo)  printf "Da drumma\n";;
  (*)      printf "Management, perhaps?\n";;
esac

On another note, if you can you should avoid unportable bashisms like the [[ test operator (and use [ if you can, e.g. if [ "$1" = "John" ]; then ...; fi.)

Jens
  • 69,818
  • 15
  • 125
  • 179
  • Oh it works with `(` at the beginning of the case expression? I don't have a computer to test right now. – Matthieu Jul 06 '19 at 19:40
  • See [why is `[]` preferred over `[[]]`](https://stackoverflow.com/questions/669452/is-double-square-brackets-preferable-over-single-square-brackets-in-ba) – Matthieu Jul 06 '19 at 20:04
  • @Matthieu: Thanks for the help on the [[ ]]. They are now removed. – runegjo Jul 06 '19 at 20:09
  • 2
    @runegjo it's up to you in the end: `[[ ]]` is more flexible and can be used safely if you know `bash` is available on your machines (and it usually is). – Matthieu Jul 06 '19 at 20:12
  • 1
    @Matthieu Yes, the initial `(` is optional. I always use it because I (and vi) like matched parentheses. – Jens Jul 06 '19 at 20:24
  • @Jens thanks for confirming. It also looks better (and the vi point is very valid! ;)) – Matthieu Jul 06 '19 at 20:31
  • 1
    @Jens, ...bashisms? `[[` is a ksh-ism that pretty much every extended shell has adopted, and for good reason; making `[[` syntax recognized by the parser allows features (like glob matching) that `[` can't do, and safety features (like recognizing, with complete certainty, the difference between syntax and data; whereas `[` has needed to have features marked obsolescent to avoid ambiguity). – Charles Duffy Jul 06 '19 at 20:31
  • Could the $1 varialble be validated against an array of valid values? – runegjo Jul 06 '19 at 20:36
  • 1
    @runegjo, against an *associative* array (the data structure some other languages call a map or a hash), trivially and quickly. For a regular numerically-indexed array you'd need to loop, and that would be much less efficient. – Charles Duffy Jul 06 '19 at 20:36
  • 2
    `declare -A validValues=( ["validOne"]=1 ["validTwo"]=1 ["whatever"]=1 ); if [[ ${validValues[$myValue]} ]]; then echo "$myValue is listed as valid"; fi` – Charles Duffy Jul 06 '19 at 20:37
  • @CharlesDuffy your comment is a better answer than my answer :) – Matthieu Jul 06 '19 at 20:58