Difference Between ${} and $() in Bash

Difference between ${} and $() in Bash

The syntax is token-level, so the meaning of the dollar sign depends on the token it's in. The expression $(command) is a modern synonym for `command` which stands for command substitution; it means run command and put its output here. So

echo "Today is $(date). A fine day."

will run the date command and include its output in the argument to echo. The parentheses are unrelated to the syntax for running a command in a subshell, although they have something in common (the command substitution also runs in a separate subshell).

By contrast, ${variable} is just a disambiguation mechanism, so you can say ${var}text when you mean the contents of the variable var, followed by text (as opposed to $vartext which means the contents of the variable vartext).

The while loop expects a single argument which should evaluate to true or false (or actually multiple, where the last one's truth value is examined -- thanks Jonathan Leffler for pointing this out); when it's false, the loop is no longer executed. The for loop iterates over a list of items and binds each to a loop variable in turn; the syntax you refer to is one (rather generalized) way to express a loop over a range of arithmetic values.

A for loop like that can be rephrased as a while loop. The expression

for ((init; check; step)); do
body
done

is equivalent to

init
while check; do
body
step
done

It makes sense to keep all the loop control in one place for legibility; but as you can see when it's expressed like this, the for loop does quite a bit more than the while loop.

Of course, this syntax is Bash-specific; classic Bourne shell only has

for variable in token1 token2 ...; do

(Somewhat more elegantly, you could avoid the echo in the first example as long as you are sure that your argument string doesn't contain any % format codes:

date +'Today is %c. A fine day.'

Avoiding a process where you can is an important consideration, even though it doesn't make a lot of difference in this isolated example.)

What's the difference between [ and [[ in Bash?

[[ is bash's improvement to the [ command. It has several enhancements that make it a better choice if you write scripts that target bash. My favorites are:

  1. It is a syntactical feature of the shell, so it has some special behavior that [ doesn't have. You no longer have to quote variables like mad because [[ handles empty strings and strings with whitespace more intuitively. For example, with [ you have to write

    if [ -f "$file" ]

    to correctly handle empty strings or file names with spaces in them. With [[ the quotes are unnecessary:

    if [[ -f $file ]]
  2. Because it is a syntactical feature, it lets you use && and || operators for boolean tests and < and > for string comparisons. [ cannot do this because it is a regular command and &&, ||, <, and > are not passed to regular commands as command-line arguments.

  3. It has a wonderful =~ operator for doing regular expression matches. With [ you might write

    if [ "$answer" = y -o "$answer" = yes ]

    With [[ you can write this as

    if [[ $answer =~ ^y(es)?$ ]]

    It even lets you access the captured groups which it stores in BASH_REMATCH. For instance, ${BASH_REMATCH[1]} would be "es" if you typed a full "yes" above.

  4. You get pattern matching aka globbing for free. Maybe you're less strict about how to type yes. Maybe you're okay if the user types y-anything. Got you covered:

    if [[ $ANSWER = y* ]]

Keep in mind that it is a bash extension, so if you are writing sh-compatible scripts then you need to stick with [. Make sure you have the #!/bin/bash shebang line for your script if you use double brackets.

See also

  • Bash FAQ - "What is the difference between test, [ and [[ ?"
  • Bash Practices - Bash Tests
  • Server Fault - What is the difference between double and single brackets in bash?

What is the difference between $(command) and `command` in shell programming?

The backticks/gravemarks have been deprecated in favor of $() for command substitution because $() can easily nest within itself as in $(echo foo$(echo bar)). There are other differences such as how backslashes are parsed in the backtick/gravemark version, etc.

See BashFAQ/082 for several reasons to always prefer the $(...) syntax.

Also see the POSIX spec for detailed information on the various differences.

What is the difference between ${var}, $var, and ${var} in the Bash shell?

Braces ($var vs. ${var})

In most cases, $var and ${var} are the same:

var=foo
echo $var
# foo
echo ${var}
# foo

The braces are only needed to resolve ambiguity in expressions:

var=foo
echo $varbar
# Prints nothing because there is no variable 'varbar'
echo ${var}bar
# foobar

Quotes ($var vs. "$var" vs. "${var}")

When you add double quotes around a variable, you tell the shell to treat it as a single word, even if it contains whitespaces:

var="foo bar"
for i in "$var"; do # Expands to 'for i in "foo bar"; do...'
echo $i # so only runs the loop once
done
# foo bar

Contrast that behavior with the following:

var="foo bar"
for i in $var; do # Expands to 'for i in foo bar; do...'
echo $i # so runs the loop twice, once for each argument
done
# foo
# bar

As with $var vs. ${var}, the braces are only needed for disambiguation, for example:

var="foo bar"
for i in "$varbar"; do # Expands to 'for i in ""; do...' since there is no
echo $i # variable named 'varbar', so loop runs once and
done # prints nothing (actually "")

var="foo bar"
for i in "${var}bar"; do # Expands to 'for i in "foo barbar"; do...'
echo $i # so runs the loop once
done
# foo barbar

Note that "${var}bar" in the second example above could also be written "${var}"bar, in which case you don't need the braces anymore, i.e. "$var"bar. However, if you have a lot of quotes in your string these alternative forms can get hard to read (and therefore hard to maintain). This page provides a good introduction to quoting in Bash.

Arrays ($var vs. $var[@] vs. ${var[@]})

Now for your array. According to the bash manual:

Referencing an array variable without a subscript is equivalent to referencing the array with a subscript of 0.

In other words, if you don't supply an index with [], you get the first element of the array:

foo=(a b c)
echo $foo
# a

Which is exactly the same as

foo=(a b c)
echo ${foo}
# a

To get all the elements of an array, you need to use @ as the index, e.g. ${foo[@]}. The braces are required with arrays because without them, the shell would expand the $foo part first, giving the first element of the array followed by a literal [@]:

foo=(a b c)
echo ${foo[@]}
# a b c
echo $foo[@]
# a[@]

This page is a good introduction to arrays in Bash.

Quotes revisited (${foo[@]} vs. "${foo[@]}")

You didn't ask about this but it's a subtle difference that's good to know about. If the elements in your array could contain whitespace, you need to use double quotes so that each element is treated as a separate "word:"

foo=("the first" "the second")
for i in "${foo[@]}"; do # Expands to 'for i in "the first" "the second"; do...'
echo $i # so the loop runs twice
done
# the first
# the second

Contrast this with the behavior without double quotes:

foo=("the first" "the second")
for i in ${foo[@]}; do # Expands to 'for i in the first the second; do...'
echo $i # so the loop runs four times!
done
# the
# first
# the
# second

What is the difference between . and ./ in bash?

The shell uses spaces to separate the command to run and its parameters.

In the first example, the command to run is . with a parameter of a.out. The . command is a shell shortcut for source, which takes the name of a file containing shell commands as its first parameter and runs those commands in the current shell. This command fails because a.out is a binary file, not a shell script.

In the second example, the command to run is ./a.out, which means run the file a.out residing in the current directory.

What is the difference between $VAR ${VAR} and $(VAR) in bash?

Let's take one command at a time:

echo $ABCHOME

The $ is a unary operator which indicates that expansion (or "substitution" if you like) is to take place. With no brackets it gives the value of the variable which follows. If the variable value contains whitespace then that whitespace will be used as an argument separator to the command, so I recommend:

echo "$ABCHOME"

Note: double quotes not single. Like brackets, different quote characters have different uses.

Using { }:

echo ${ABCHOME}

With no other characters, the braces are used to delimit the variable name when embedded in other text, and are rarely required (although they are benign). For example: echo "$ABCHOMEandaway" would fail, but echo "${ABCHOME}andaway" would append "andaway" to the value text. The recommendations with quotes also apply here.

Braces, ${ } also introduce other variable expansion syntax when the variable name is followed by a special character like a colon : or a /. That is probably too advanced for you right now, put that on your list for learning later.

Using $( ):

echo $(ABCHOME)

This expansion is command substitution, where the command specified inside the parentheses is run and the standard output captured and returned to the script. Of course, there is no command called ABCHOME, so you get:

bash: ABCHOME: command not found

As a general rule, brackets cannot be exchanged without thought in any programming language. Bash syntax can be complex and non-intuitive. Follow a tutorial (there are lots available). Play by all means, but use the man bash pages to discover the syntax you are using.

What is the difference between backticks and $() in a Bash script?

There isn't any semantic difference. The backtick syntax is the older and less powerful version. See man bash, section "Command Substitution".

If your shell supports the $() syntax, prefer it because it can be nested.

Difference between single and double quotes in Bash

Single quotes won't interpolate anything, but double quotes will. For example: variables, backticks, certain \ escapes, etc.

Example:

$ echo "$(echo "upg")"
upg
$ echo '$(echo "upg")'
$(echo "upg")

The Bash manual has this to say:

3.1.2.2 Single Quotes

Enclosing characters in single quotes (') preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.

3.1.2.3 Double Quotes

Enclosing characters in double quotes (") preserves the literal value of all characters within the quotes, with the exception of $, `, \, and, when history expansion is enabled, !. The characters $ and ` retain their special meaning within double quotes (see Shell Expansions). The backslash retains its special meaning only when followed by one of the following characters: $, `, ", \, or newline. Within double quotes, backslashes that are followed by one of these characters are removed. Backslashes preceding characters without a special meaning are left unmodified. A double quote may be quoted within double quotes by preceding it with a backslash. If enabled, history expansion will be performed unless an ! appearing in double quotes is escaped using a backslash. The backslash preceding the ! is not removed.

The special parameters * and @ have special meaning when in double quotes (see Shell Parameter Expansion).



Related Topics



Leave a reply



Submit