3

In specifically Bash version 4.0.0, is there any way to work around the use of an empty $@ raising an unbound variable error when set -u is enabled?

Consider the following:

#!/usr/bin/env bash-4.0.0-1

set -xvu

echo "$BASH_VERSION"
echo "${BASH_VERSINFO[@]}"

main () {
  printf '%q\n' "${@:-}"
}

main "${@:-}"

Gives me the following output when I provide an empty set of arguments:

neech@nicolaw.uk:~ $ ./test.sh

echo "$BASH_VERSION"
+ echo '4.0.0(1)-release'
4.0.0(1)-release
echo "${BASH_VERSINFO[@]}"
+ echo 4 0 0 1 release x86_64-unknown-linux-gnu
4 0 0 1 release x86_64-unknown-linux-gnu

main () {
  printf '%q\n' "${@:-}"
}

main "${@:-}"
./test.sh: line 12: $@: unbound variable

I only see this behaviour in Bash version 4.0.0.

I was hoping that using variable substitution ${@:-} would allow me to work around this, but it seems not.

Is there a way to work around this?

  • Do you have any significant reason for not simply upgrading to a newer version of `bash`? 4.0.0 is over 8 years old at this point and is four releases out of date; if it weren't for the special case of macOS clinging to 3.2, I don't think anyone would ever hesitate to suggest using *at least* 4.2, if not 4.3. – chepner Jun 15 '17 at 13:21
  • 2
    The other work around is simply to turn off `set -u` once your script is reasonably debugged. If you are concerned about variables being unset for reasons other than simple typos, check explicitly before using them. – chepner Jun 15 '17 at 13:22
  • As @chepner mentioned, better to do exception handling on your own rather than relying on set -u. – Jacek Trociński Jun 09 '18 at 07:25

2 Answers2

7

$@, $* are special variables so should always be defined it's a bug

https://unix.stackexchange.com/questions/16560/bash-su-unbound-variable-with-set-u

a workaround, maybe:

set +u
args=("$@")
set -u

main "${args[@]}"

or maybe also

main "${@:+$@}"
Nahuel Fouilleul
  • 18,726
  • 2
  • 31
  • 36
0

Why not do error handling on your own? This way you can control exactly what happens when an exception is encountered, for instance return a custom exit code and message for that error, rather than be confined to some predefined behavior.

function log_error                                                          
{                                                                           
    [[ $# -ne 1 ]] && return 1                                              

    typeset msg="$1"                                                        
    typeset timestamp=$(date "+%F %T")                                      

    echo "[${timestamp}] [ERROR] - $msg " >&2                               
}

if [[ -z "$BASH_VERSION" ]]                                                 
then                                                                        
    log_error "BASH VERSION is not set"                                     
    exit 1                                                                  
fi 
Jacek Trociński
  • 882
  • 1
  • 8
  • 23