I can write
VAR=$VAR1
VAR=${VAR1}
VAR="$VAR1"
VAR="${VAR1}"
the end result to me all seems about the same. Why should I write one or the other? are any of these not portable/POSIX?
VAR=$VAR1
is a simplified version of VAR=${VAR1}
. There are things the second can do that the first can't, for instance reference an array index (not portable) or remove a substring (POSIX-portable). See the More on variables section of the Bash Guide for Beginners and Parameter Expansion in the POSIX spec.
Using quotes around a variable as in rm -- "$VAR1"
or rm -- "${VAR}"
is a good idea. This makes the contents of the variable an atomic unit. If the variable value contains blanks (well, characters in the $IFS
special variable, blanks by default) or globbing characters and you don't quote it, then each word is considered for filename generation (globbing) whose expansion makes as many arguments to whatever you're doing.
$ find .
.
./*r*
./-rf
./another
./filename
./spaced filename
./another spaced filename
./another spaced filename/x
$ var='spaced filename'
# usually, 'spaced filename' would come from the output of some command and you weren't expecting it
$ rm $var
rm: cannot remove 'spaced': No such file or directory
# oops! I just ran 'rm spaced filename'
$ var='*r*'
$ rm $var
# expands to: 'rm' '-rf' '*r*' 'another spaced filename'
$ find .
.
./another
./spaced filename
./another spaced filename
$ var='another spaced filename'
$ rm -- "$var"
$ find .
.
./another
./spaced filename
On portability: According to POSIX.1-2008 section 2.6.2, the curly braces are optional.
var1=$var
expansion gives an error?
export VAR=$VAR1
. As for the braces, they are optional (check the fourth paragraph of the section you cited; this is the case in all pre-POSIX and POSIX shells).
Commented
Dec 16, 2010 at 19:13
${VAR}
and $VAR
are exactly equivalent. For a plain variable expansion, the only reason to use ${VAR}
is when parsing would otherwise grab too many characters into the variable name, as in ${VAR1}_$VAR2
(which without braces would be equivalent to ${VAR1_}$VAR2
). Most adorned expansions (${VAR:=default}
, ${VAR#prefix}
, …) require braces.
In csh, tcsh or zsh (when the ksharrays
option is not enabled), $var[1]
is the same as ${var[1]}
and $var:modifier
the same as ${var:modifier}
, so you also want the braces there if you want the $var
expansion followed by a literal [1]
or :modifier
: ${var}[1]
${var}:modifier
.
In a scalar (as opposed to array or associative array) variable assignment, field splitting (i.e. splitting at whitespace in the value) and pathname expansion (i.e. globbing) are turned off, so VAR=$VAR1
is exactly equivalent to VAR="$VAR1"
, in all POSIX shells and in all pre-POSIX sh that I've heard of. (POSIX ref: simple commands). For the same reason, VAR=*
reliably sets VAR
to the literal string *
; of course VAR=a b
sets VAR
to a
since the b
is a separate word in the first place. Generally speaking, double quotes are unnecessary where the shell syntax expects a single word, for example in case … in
(but not in the pattern), but even there you need to be careful: for example POSIX specifies that redirection targets (>$filename
) don't require quoting in scripts, but a few shells including bash do require the double quotes even in scripts. See When is double-quoting necessary? for a more thorough analysis.
You do need the double quotes in other cases, in particular in export VAR="${VAR1}"
(which can equivalently be written export "VAR=${VAR1}"
) in many shells (POSIX leaves this case open). The similarity of this case with simple assignments, and the scattered nature of the list of cases where you don't need double quotes, are why I recommend just using double quotes unless you do want to split and glob.
IFS
characters because I want to be in the habit. The one exception is I don't quote the value when doing a variable assignment (unless required, such as when the value contains a space). This makes editor syntax highlighting more useful when there are command substitutions such as FOO=$(BAR=$(BAZ=blah; printf %s "${BAZ}"); printf %s "${BAR}")
. Rather than coloring everything the "string" color, I get syntax highlighting of the nested code. This is also why I avoid backticks.
Commented
Jan 4, 2013 at 19:19
>$file
is OK in POSIX scripts, it is not in bash even when non-interactive (unless POSIX compliance is enforced with $POSIXLY_CORRECT
or --posix
...).
Commented
Jan 23, 2013 at 15:01
VAR=$VAR1
, I've been surprised sometimes by local VAR=$VAR1
, which I remember working differently in some respects, in at least some shells. But atm, I can't reproduce the divergence.
Commented
Sep 19, 2015 at 8:31
local VAR=$VAR1
is like export VAR=$VAR1
, it depends on the shell.
Commented
Sep 19, 2015 at 13:17
Consider that double-quote is used for variable expansion, and single-quote is used for strong-quoting, i.e., sans expansion.
this='foo'
that='bar'
these="$this"
those='$that'
for item in "$this" "$that" "$these" "$those"; do echo "$item"; done
foo
bar
foo
$that
It might be worthwhile to mention that you should use quotation wherever possible for several reasons, among the best of which are that it's considered best practice, and for readability. Also because Bash is quirky at times and often for seemingly illogical or unreasonable/unexpected ways, and quotation changes implicit expectations to explicit, which reduces that error surface (or potential-for therein).
And while it's completely legal to not quote, and will work in most cases, that functionality is provided for convenience and is probably less portable. the fully-formal practice guaranteed to reflect intent and expectation is to quote.
Now consider also that the construct "${somevar}"
is used for substitution operations. Several use cases, such as replacement, and arrays.
thisfile='foobar.txt.bak'
foo="${thisfile%.*}" # removes shortest part of value in $thisfile matching after '%' from righthand side
bar="${thisfile%%.*}" # removes longest matching
for item in "$foo" "$bar"; do echo "$item"; done
foobar.txt
foobar
foobar='Simplest, least effective, least powerful'
# ${var/find/replace_with}
foo="${foobar/least/most}" #single occurrence
bar="${foobar//least/most}" #global occurrence (all)
for item in "$foobar" "$foo" "$bar"; do echo "$item"; done
Simplest, least effective, least powerful
Simplest, most effective, least powerful
Simplest, most effective, most powerful
mkdir temp
# create files foo.txt, bar.txt, foobar.txt in temp folder
touch temp/{foo,bar,foobar}.txt
# alpha is array of output from ls
alpha=($(ls temp/*))
echo "$alpha" # temp/foo.txt
echo "${alpha}" # temp/foo.txt
echo "${alpha[@]}" # temp/bar.txt temp/foobar.txt temp/foo.txt
echo "${#alpha}" # 12 # length of first element (implicit index [0])
echo "${#alpha[@]}" # 3 # number of elements
echo "${alpha[1]}" # temp/foobar.txt # second element
echo "${#alpha[1])" # 15 # length of second element
for item in "${alpha[@]}"; do echo "$item"; done
temp/bar.txt
temp/foobar.txt
temp/foo.txt
All of this is barely scratching the surface of the "${var}"
substitution construct. The definitive reference for Bash shell scripting is the libre online reference, TLDP The Linux Documentation Project https://www.tldp.org/LDP/abs/html/parameter-substitution.html