what is the difference between $1 and “$1” in bash script? [duplicate]


what is the difference between $1 and “$1” in bash script? [duplicate]



This question already has an answer here:



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


$1


"$1"


user=alexander


user="alexander"



This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.





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 entries than any other single class of error.
– Charles Duffy
Jun 30 at 3:33





2 Answers
2


$ 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





Please avoid all-caps variable names in examples -- see fourth paragraph of the relevant POSIX spec at pubs.opengroup.org/onlinepubs/9699919799/basedefs/…, 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 at 3:35



for PATH in */





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 at 3:38



IFS


set -- '*'


echo "$1"


echo $1


shopt -s failglob; set -- '[name]-with-brackets'; echo $1





@CharlesDuffy Thank you. Can I use your comments to expand my answer?
– AmokHuginnsson
Jun 30 at 3:42





By all means do.
– Charles Duffy
Jun 30 at 3:43



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.


$foo


bar


baz


bar baz



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.


$1





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 goes into several of the ways this fails (and why other mechanisms, such as arrays, should be used instead).
– Charles Duffy
Jun 30 at 3:41

Comments

Popular posts from this blog

paramiko-expect timeout is happening after executing the command

how to run turtle graphics in Colaboratory

Export result set on Dbeaver to CSV