Differences between revisions 5 and 22 (spanning 17 versions)
Revision 5 as of 2007-09-14 13:13:13
Size: 2511
Editor: GreyCat
Comment: several changes
Revision 22 as of 2013-01-24 10:53:38
Size: 3064
Editor: ormaaj
Comment: UUOE. Still not a great example.
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
[[Anchor(faq82)]] <<Anchor(faq82)>>
Line 3: Line 3:
{{{`...`}}} is the legacy syntax required by only the very oldest of non-POSIX-compatible bourne-shells. There are several reasons to always prefer the {{{$(...)}}} syntax:
Line 4: Line 5:
For several reasons: === Important differences ===

 * Backslashes (\) inside backticks are handled in a non-obvious manner:
  {{{
  $ echo "`echo \\a`" "$(echo \\a)"
  a \a
  $ echo "`echo \\\\a`" "$(echo \\\\a)"
  \a \\a
  # Note that this is true for *single quotes* too!
  $ foo=`echo '\\'`; bar=$(echo '\\'); echo "foo is $foo, bar is $bar"
  foo is \, bar is \\
  }}}

 * Nested quoting inside {{{$()}}} is far more convenient.
  {{{
  echo "x is $(sed ... <<<"$y")"
  }}}
  In this example, the quotes around {{{$y}}} are treated as a pair, because they are inside {{{$()}}}. This is confusing at first glance, because most C programmers would expect the quote before {{{x}}} and the quote before {{{$y}}} to be treated as a pair; but that isn't correct in shells. On the other hand,
  {{{
  echo "x is `sed ... <<<\"$y\"`"
  }}}
  requires backslashes around the internal quotes in order to be portable. Bourne and Korn shells require these backslashes, while Bash and dash don't.
Line 8: Line 30:
  x=$(grep $(dirname "$path") file)
  x=`grep \`dirname "$path"\` file`}}}
 It just gets uglier and uglier after two levels.
  x=$(grep "$(dirname "$path")" file)
  x=`grep "\`dirname "$path"\`" file`
  }}}
  
It just gets uglier and uglier after two levels. {{{$()}}} forces an entirely new context for quoting, so that everything within the command substitution is protected and can be treated as though it were on its own, with no special concern over quoting and escaping.
Line 12: Line 35:
 * It's easier to read. === Other advantages ===
Line 14: Line 37:
 * Newbies who see {{{$()}}} don't normally press the wrong keys. On the other hand, newbies who see {{{`cmd`}}} often mangle it into {{{'cmd'}}} because they don't know what a backtick is.  * The function of {{{$(...)}}} as being an expansion is visually clear. The syntax of a {{{$}}}-prefixed token is consistent with all other expansions that are parsed from within double-quotes, at the same time, from left-to-right. Backticks are the only exception. This improves human and machine readability, and consistent syntax makes the language more intuitive for readers.
Line 16: Line 39:
 * Backslashes (\) inside backticks are handled in a non-obvious manner:
  {{{
  echo "`echo \\a`" # prints a
  echo "`echo \\\a`" # prints \a
  echo "`echo \\\\a`" # prints \a}}}
 Inside {{{$()}}}, there are no such surprises.
 * Per the above, people are (hopefully) accustomed to seeing double-quoted expansions and substitutions with the usual {{{"$..."}}} syntax. Quoting command substitutions is almost always the correct thing to do, yet the great majority of {{{`...`}}} specimens we find in the wild are left unquoted, perhaps because those who still use the legacy syntax are less experienced, or they don't associate it with the other expansions due to the different syntax. In addition, the {{{`}}} character is easily camouflaged when adjacent to {{{"}}} making it even more difficult to read, especially with small or unusual fonts.
Line 23: Line 41:
 * Nested quoting inside {{{$()}}} is far more convenient.
  {{{
  echo "x is $(echo "$y" | sed ...)"}}}
 In this example, the quotes around {{{$y}}} are treated as a pair, because they are inside {{{$()}}}. This is confusing at first glance, because most C programmers would expect the quote before {{{x}}} and the quote before {{{$y}}} to be treated as a pair; but that isn't correct in shells. On the other hand,
  {{{
  echo "x is `echo \"$y\" | sed ...`"}}}
 requires backslashes around the internal quotes in order to be portable. Bourne and Korn shells require these backslashes, while Bash and dash don't.
 * The backtick is also easily confused with a single quote.
Line 31: Line 43:
Backslashes are no more no less surprising than elsewhere IMHO
{{{
  echo `echo \a` # prints a
  echo `echo \\a` # prints a
  echo `echo \\\a` # prints \a
  echo `echo \\\\a` # prints \a
  echo $(echo \a) # prints a
  echo $(echo \\a) # prints \a
  echo $(echo \\\a) # prints \a
  echo $(echo \\\\a) # prints \\a
}}}
The same sort of things happens without any quotes or within "".

I suspect the real advantage of $( ) here is that you don't need to take extra care of the quotes (\ ""), you just put them as usual, ie
{{{echo "`echo \"foo bar\"`"}}} vs {{{echo "$( echo "foo bar")"}}} -- pgas
 ''Just for the record, \" inside {{{`backticks`}}} is only required in Korn shell and Bourne shell. Bash and dash both treat''
 {{{
 echo "`echo "foo bar"`"}}}
 ''exactly the same way they treat''
 {{{
 echo "$(echo "foo bar")"}}}
 ''although this is an excellent point that I'm going to add to the bullet list up above.'' -- GreyCat

The only time backticks are preferred is when writing code for the oldest Bourne shells, which do not know about {{{$()}}}.
=== See also: ===
 * [[http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_03|POSIX standard and section "2.6.3 Command Substitution"]]
 * [[CommandSubstitution]]
 * [[http://wiki.bash-hackers.org/syntax/expansion/cmdsubst|bash-hackers: command substitution]]

Why is $(...) preferred over `...` (backticks)?

`...` is the legacy syntax required by only the very oldest of non-POSIX-compatible bourne-shells. There are several reasons to always prefer the $(...) syntax:

Important differences

  • Backslashes (\) inside backticks are handled in a non-obvious manner:
    •   $ echo "`echo \\a`" "$(echo \\a)"
        a \a
        $ echo "`echo \\\\a`" "$(echo \\\\a)"
        \a \\a
        # Note that this is true for *single quotes* too!
        $ foo=`echo '\\'`; bar=$(echo '\\'); echo "foo is $foo, bar is $bar" 
        foo is \, bar is \\
  • Nested quoting inside $() is far more convenient.

    •   echo "x is $(sed ... <<<"$y")"

      In this example, the quotes around $y are treated as a pair, because they are inside $(). This is confusing at first glance, because most C programmers would expect the quote before x and the quote before $y to be treated as a pair; but that isn't correct in shells. On the other hand,

        echo "x is `sed ... <<<\"$y\"`"
      requires backslashes around the internal quotes in order to be portable. Bourne and Korn shells require these backslashes, while Bash and dash don't.
  • It makes nesting command substitutions easier. Compare:
    •   x=$(grep "$(dirname "$path")" file)
        x=`grep "\`dirname "$path"\`" file`

      It just gets uglier and uglier after two levels. $() forces an entirely new context for quoting, so that everything within the command substitution is protected and can be treated as though it were on its own, with no special concern over quoting and escaping.

Other advantages

  • The function of $(...) as being an expansion is visually clear. The syntax of a $-prefixed token is consistent with all other expansions that are parsed from within double-quotes, at the same time, from left-to-right. Backticks are the only exception. This improves human and machine readability, and consistent syntax makes the language more intuitive for readers.

  • Per the above, people are (hopefully) accustomed to seeing double-quoted expansions and substitutions with the usual "$..." syntax. Quoting command substitutions is almost always the correct thing to do, yet the great majority of `...` specimens we find in the wild are left unquoted, perhaps because those who still use the legacy syntax are less experienced, or they don't associate it with the other expansions due to the different syntax. In addition, the ` character is easily camouflaged when adjacent to " making it even more difficult to read, especially with small or unusual fonts.

  • The backtick is also easily confused with a single quote.

See also:

BashFAQ/082 (last edited 2022-02-19 00:13:59 by larryv)