0

I thought that variable expansions should always be quoted. Lately, I'm seeing more and more examples in reputable source that do not quote variables in certain instances. However, I can't see a clear rule that states when exactly that is the case.

An example, taken from the excellent answer to this question:

POSITIONAL=()
while [[ $# -gt 0 ]]
do
key="$1"

case $key in
    -e|--extension)
    EXTENSION="$2"
    shift # past argument
    shift # past value
    ;;
    -s|--searchpath)
    SEARCHPATH="$2"
    shift # past argument
    shift # past value
    ;;
    -l|--lib)
    LIBPATH="$2"
    shift # past argument
    shift # past value
    ;;
    --default)
    DEFAULT=YES
    shift # past argument
    ;;
    *)    # unknown option
    POSITIONAL+=("$1") # save it in an array for later
    shift # past argument
    ;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters

Why are $# and $key not quoted? There are many more examples in that answer. In fact, in the first example there it's tail -1 "$1" and in the second it's tail -1 $1.

shellcheck.net doesn't care if I write key="$1" or key=$1, but it does care when it's an argument to tail.

iuvbio
  • 600
  • 6
  • 23
  • 2
    There are some situations where quoting isn't necessary, but the rules are complicated and it's easier and safer to just always double-quote (unless there's a specific reason not to). See the Unix&Linux question ["When is double-quoting necessary?"](https://unix.stackexchange.com/questions/68694/when-is-double-quoting-necessary) – Gordon Davisson Jul 23 '19 at 18:04
  • 1
    In addition to `$#` being an integer and thus not needing quoting, variables inside double square bracket expressions quoting is optional. Variables on the right side of an assignment don't need to be quoted when they're by themselves: `var1=$var2$var3`, but if there are special characters, the expression should almost always be quoted: `var1="$var2;# $var3"` – Dennis Williamson Jul 23 '19 at 22:07

1 Answers1

0

You need to supply quotes whenever you want to keep a string as-is; for instance, preserve newlines or spaces in your text.

In your example your looping over arguments, which are typically delimited by a space. You don't need the quotes here. the value of $# is an integer, which don't have newlines and spaces in them, thus making it unnecessary to quote them.

You can try this yourself:

$ mkdir tmp; cd tmp; touch a b
$ A=$(ls)
$ echo $A
total 0 -rw-rw-r-- 1 user group 0 Jul 23 19:20 a -rw-rw-r-- 1 user group 0 Jul 23 19:20 b
$ echo "$A"
total 0
-rw-rw-r-- 1 user group 0 Jul 23 19:20 a
-rw-rw-r-- 1 user group 0 Jul 23 19:20 b
$ A=">   <"
$ echo $A
> <
$ echo "$A"
>   <
Bayou
  • 3,293
  • 1
  • 9
  • 22