0

example

while [ -n "$1" ]
do
  something
done

can i write $1 instead of "$1"? And what is the difference between user=alexander and user="alexander"? Thanks

dbush
  • 205,898
  • 23
  • 218
  • 273
epsilon
  • 868
  • 2
  • 8
  • 17
  • 2
    The shell does substantially more processing on unquoted strings than on quoted ones (not just splitting them up on whitespace or characters in IFS, but also expanding each of the post-split components as a glob) -- and in 99% of cases that processing is undesired. Missing quotes are probably responsible for more [BashPitfalls](http://mywiki.wooledge.org/BashPitfalls) entries than any other single class of error. – Charles Duffy Jun 30 '18 at 03:33

2 Answers2

6
$ var="two words"
$ function num_args() { echo "${#}"; }
$ num_args $var
2
$ num_args "$var"
1

The difference between $A and "$A" is how word breaks are treated with respect to passing arguments to programs and functions.

Imagine script that works on files (let's say moves them around):

$ cat my-move
#! /bin/sh
# my-move

src=${1}
dst=${2}

# ... do some fancy business logic here

mv ${src} ${dst}
$ my-move "some file" other/path

As the code stands now (no quotes) this script is broken as it will not handle file paths with spaces in them correctly.

(Following thanks to @CharlesDuffy)

Additionally quoting matters when handling glob patterns:

$ var='*'
$ num_args "$var"
1
$ num_args $var
60

Or:

$ shopt -s failglob
$ var='[name]-with-brackets'
$ echo $var
bash: no match: [name]-with-brackets
$ echo "$var"
[name]-with-brackets
AmokHuginnsson
  • 1,174
  • 10
  • 14
  • 1
    Please avoid all-caps variable names in examples -- see fourth paragraph of the relevant POSIX spec at http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html, specifying that POSIX-compliant shells and tools will only modify their behavior in response to all-caps variable names, *and reserving names with at least one lowercase character for application use*. Following this convention avoids situations like `for PATH in */` and suddenly no longer being able to run external commands. – Charles Duffy Jun 30 '18 at 03:35
  • 1
    BTW, it's not just strings that can be split on whitespace or `IFS` characters where quoting matters. Run `set -- '*'` and compare `echo "$1"` and `echo $1`; or `shopt -s failglob; set -- '[name]-with-brackets'; echo $1` compared against the same with quotes. – Charles Duffy Jun 30 '18 at 03:38
  • @CharlesDuffy Thank you. Can I use your comments to expand my answer? – AmokHuginnsson Jun 30 '18 at 03:42
  • By all means do. – Charles Duffy Jun 30 '18 at 03:43
1

The quotes act as a way to group the argument regardless of the presence of spaces or other special characters. By way of demonstration, here's a case where the two are materially different:

$ foo="bar baz"
$ sh -c 'echo $1' worker $foo
bar
$ sh -c 'echo $1' worker "$foo"
bar baz

In the above example we pass $foo without quotes, which passes bar as argument 1 and baz as argument two, but when we pass it with quotes it passes bar baz as argument 1.

So while you can write a variable without quotes (e.g. $1), it is generally best practice to wrap it in quotes, unless you are specifically looking for it to be potentially treated as several independent arguments.

Matthew Story
  • 3,573
  • 15
  • 26
  • Even if you *do* want a string's contents to be treated as several independent arguments, just leaving out the quotes will often not behave as desired; [BashFAQ #50](http://mywiki.wooledge.org/BashFAQ/050) goes into several of the ways this fails (and why other mechanisms, such as arrays, should be used instead). – Charles Duffy Jun 30 '18 at 03:41