2

Bash Strict Mode is defined as follows:

#!/bin/bash
set -euo pipefail
IFS=$'\n\t'

http://redsymbol.net/articles/unofficial-bash-strict-mode/

Consider the following parsing of positional parameters in a Bash script:

#!/bin/bash
set -euo pipefail
IFS=$'\n\t'

usage() { echo "" echo "usage:" echo "$0 [options]" echo " -r | --redirect-uri: redirect uri" echo " -a | --app-role: app role id" echo " -h | --help: help" echo "" }

redirect_uri="" app_role=""

while [ "$1" != "" ]; do case $1 in -r | --redirect-uri) shift redirect_uri="$1" ;; -a | --app-role) shift app_role="$1" ;; -h | --help) usage exit 0 ;; *) usage exit 1 ;; esac shift done

...

This doesn't work with the following error, e.g.:

$ ./app.sh -r https://example.net:8080/auth/callback -a 53b37b21-2c6e-4731-a5e5-15b98052c686        
./app.sh: line 18: $1: unbound variable

I think the reason is the final check in the while condition, after shift, where $1 is undefined.

How can I terminate parameter parsing in the while statement without causing the script to crash, when using Bash Strict Mode?

Shuzheng
  • 4,411
  • Which not consistently using the long more self described options like set -o errexit -o nounset -o pipefail? (btw, there's nothing bash-specific in those). – Stéphane Chazelas Apr 04 '23 at 09:43
  • Aren't those options Bash specific? – Shuzheng Apr 04 '23 at 10:11
  • 1
    While set -u can be useful at least as a development helper, I'd be really wary of things like set -e esp. in connection with pipefail. If you ever use pipelines, I'd wager that will cause your script to mysteriously fail without you having any idea why it happens. – ilkkachu Apr 04 '23 at 12:54

1 Answers1

5

You get the unbound variable error since you are trying to access $1 when it's not defined, which it won't be after the last iteration of the while loop. So, the problematic command is the test that you use with while:

[ "$1" != "" ]

Instead, use something like

[ "${1+set}" = set ]

or

[ -n "${1+set}" ]

The parameter expansion ${parameter+word} will expand to word if parameter is an existing variable (regardless of whether it has a non-empty value or not). The word set was chosen arbitrarily, but in a way that hints at what it's used for.

You could also test on $#, which holds the number of positional parameters:

[ "$#" -ne 0 ]

or

[ "$#" -gt 0 ]

These are arithmetic tests that are true whenever there are positional parameters that still need to be processed and shifted off the list.

Either of these variations avoids bumping against the restrictions imposed by the nounset shell option (set -u).

Kusalananda
  • 333,661