Reputation: 425
Given the following code in bash:
filename=${1}
content1=${@:2}
content2="${@:2}"
content3=${*:2}
content4="${*:2}"
echo "${content1}" > "${filename}"
echo "${content2}" >> "${filename}"
echo "${content3}" >> "${filename}"
echo "${content4}" >> "${filename}"
What is the difference between the "contents" ? When I will see the difference? What is the better way to save the content that I get and why?
Upvotes: 0
Views: 242
Reputation: 52112
In an assignment, the right-hand side doesn't have to be quoted to prevent word splitting and globbing, unless it contains a blank.
These two are the same:
myvar=$var
myvar="$var"
but these are not:
myvar='has space'
myvar=has space
The last one tries to run a command space
with the environment variable myvar
set to value has
.
This means that content1
is the same as content2
, and content3
is the same as content4
, as they only differ in RHS quoting.
The differences thus boil down to the difference between $@
and $*
; the fact that subarrays are used doesn't matter. Quoting from the manual:
(for $*
):
When the expansion occurs within double quotes, it expands to a single word with the value of each parameter separated by the first character of the
IFS
special variable.
(for $@
):
When the expansion occurs within double quotes, each parameter expands to a separate word.
Since you're using quotes (as you almost always should when using $@
or $*
), the difference is that "${*:2}"
is a single string, separated by the first character of IFS
, and "${@:2}"
expands to separate words, blank separated.
Example:
$ set -- par1 par2 par3 # Set $1, $2, and $3
$ printf '<%s>\n' "${@:2}" # Separate words
<par2>
<par3>
$ printf '<%s>\n' "${*:2}" # Single word, blank separated (default IFS)
<par2 par3>
$ IFS=, # Change IFS
$ printf '<%s>\n' "${*:2}" # Single word, comma separated (new IFS)
<par2,par3>
As for when to use $@
vs. $*
: as a rule of thumb, you almost always want "$@"
and almost never the unquoted version of either, as the latter is subject to word splitting and globbing.
"$*"
is useful if you want to join array elements into a single string as in the example, but the most common case, I guess, is iterating over positional parameters in a script or function, and that's what "$@"
is for. See also this Bash Pitfall.
Upvotes: 2
Reputation: 530940
The only difference is that using $*
will cause the arguments to be concatenated with the first character of IFS
, while $@
will cause the arguments to be concatenated with a single space (regardless of the value of IFS
):
$ set a b c
$ IFS=-
$ c1="$*"
$ c2="$@"
$ echo "$c1"
a-b-c
$ echo "$c2"
a b c
The quotes aren't particularly important here, as expansions on the right-hand side of an assignment aren't subject to word-splitting or pathname expansion; content1
and content2
should always be identical, as should be content3
and content4
.
Which is better depends on what you want.
Upvotes: 1