Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any reason not to quote variables?

Tags:

bash

Is there any valid reason not to put all variables in a shell script in quotes? ("Not knowing any better" is not a valid reason in my opinion.)

Generally speaking, quoting variables makes sure that they are seen as one variable, should they contain spaces or other special characters. So why would anyone ever go for an "unsafe" way and not quote variables?

like image 346
MechMK1 Avatar asked Dec 05 '22 02:12

MechMK1


2 Answers

So why would anyone ever go for an "unsafe" way and not quote variables?

That is almost never the right thing to do. Newcomers to shell are almost always better served by placing variables in double-quotes. For advanced users, I can think of three possible exceptions:

1. You want pathname expansion.

An example could be:

glob=*.xml
# Do something, possibly creating xml files
rm $glob

Here, pathname expansion is performed on glob not when it is defined but when rm is executed. There might be times when such late evaluation is beneficial.

For bash, one can can create an array with glob=(*.xml). This is likely superior for every case except when late evaluation is important.

2. You want word splitting.

An example is handling simple command options when you want compatibility with POSIX shells that that don't support arrays:

opts=
[ -f "$onething" ] && opts="-a"
[ -f "$another" ] && opts="$opts -b"
cmd $opts

Here, word splitting allows the command cmd to see multiple options. If $opts were in quotes, it would see only one string.

This approach for multiple options is limited to simple options. For bash, one would replace the variable opts with an array which works much better when options are more complex. POSIX shells, however, do not support named arrays so using a variable like this is viable as a second-best work-around.

3. Bash's [[

Inside [[...]], you may sometimes want the operator = to test for a glob match. If so the right-hand side must be unquoted:

$ glob=*.xml
$ [[ file.xml = "$glob" ]] && echo yes || echo no
no
$ [[ file.xml =  $glob  ]] && echo yes || echo no
yes

Glob matches are handy when you want them. If you weren't expecting them, they can be a disaster. Thus, unless you explicitly want a glob match, the right-hand side must be quoted.

Likewise if you want the =~ operation to test for a regex match:

$ regex=fi.*ml
$ [[ file.xml =~ "$regex" ]] && echo yes || echo no
no
$ [[ file.xml =~  $regex  ]] && echo yes || echo no
yes

(Hat tip: Gordon Davisson)

like image 91
John1024 Avatar answered Jan 05 '23 03:01

John1024


Well, to me "reducing unnecessary syntactic noise to make the script more readable" >>could be<< a valid reason, at least in some peoples' minds.

I'm assuming that there are situations where the variable CANNOT have spaces in them; e.g.

   COUNT=1
   FILENAME=file$COUNT.txt

and that are other cases where it really doesn't matter how the embedded spaces are treated; e.g.

   echo the filename is $NAME 

But if you don't accept that as "valid" (and I think you won't from the tone of your question), then I guess the answer is No.


And obviously, there are situations where quoting would suppress behavior that you actually require; e.g. tokenization or globbing.

like image 42
Stephen C Avatar answered Jan 05 '23 03:01

Stephen C