3

I am running the following code when I have two arguments

if (( $# == 2 )); then : ${fdir:="${@:-1}"} pfm -w2 "" "unspecified -d option" echo "use last argument as substitute" printf '%s\n\n' "fdir: ${@:-1}" echo "\$1: $1 \$2: $2" 

This is the result

pregion --dyn "John" ./01cuneus pregion --dyn John ./01cuneus unspecified -d option use last argument as substitute fdir: John ./01cuneus $1: John $2: ./01cuneus 

1 Answer 1

6

No, "${@:-1}" doesn't. But "${@: -1}" does.

But note that at least in Bash and Ksh, if there are no positional parameters, then "${@: -1}" gives "$0", i.e. the shell name. This is similar to how using ${@:0} gives $0 and all positional the positional parameters. Zsh doesn't seem to give $0 with ${@: -1} or the cleaner ${@[-1]}.

The gotcha here is that ${var:-value} is a standard expansion which expands to the default value value if var is unset or empty. The substring/array slice expansion ${var:p:n}, of which ${@: -1} is a special case, is not standard and the shell interprets ${@:-1} as the default value expansion on $@. The space removes the ambiguity, and so would putting the index in a variable, e.g. i=-1; echo "${@:i}"

set -- a b c echo "${@: -1}" # prints 'c', the last element echo "${@:-1}" # prints 'a b c' set -- echo "${@: -1}" # prints '/bin/bash' or something like that echo "${@:-1}" # prints '1', the default value given echo "${@:-no args}" # prints 'no args' 

Also as noted in comments, the expansion in : ${fdir:="${@:-1}"} is unquoted, so it may cause the shell to generate an arbitrarily long list of filenames. That could be prevented with : "${fdir:="${@: -1}"}", or the perhaps more readable [ -z "$fdir"] && fdir="${@: -1}"

7
  • May also be worth noting that in : ${fdir:="${@: -1}"}, the quotes are in the wrong place as the expansion would be subject to split+glob (and even when passed to : constitute the kind of DoS vulnerability described at Security implications of forgetting to quote a variable in bash/POSIX shells Commented Jul 27, 2021 at 17:13
  • In zsh (or fish), you'd rather use $argv[-1]. Also ${@[-1]} in zsh or yash. Commented Jul 27, 2021 at 17:15
  • Then it would be safer to use ${@:$#}. Commented Jul 27, 2021 at 17:52
  • @Pietru, not sure what difference that would make. It also would give $0 if there were no positional parameters Commented Jul 27, 2021 at 18:51
  • I meant that "${@:$#}" as safer option than "${@: -1}", in case one misses the space. Commented Jul 27, 2021 at 19:13

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.