Backtick command encapsulation

6,779

Solution 1

Depends on your version of bash:

bash-4.2$ echo `echo \`echo "uh!"\``
bash: !"\``: event not found
bash-4.3$ echo `echo \`echo "uh!"\``
uh!

In bash-4.3, !" is no longer eligible as a history event designator, so history expansion does not apply.

Other than that, it's just normal backtick nesting syntax. Inside backticks, the backslash character is overloaded (yet again) to do that nested expansion again.

You can nest as many levels as you want:

echo `echo \`echo \\\`echo \\\\\\\`echo whatever\\\\\\\`\\\`\``

Which is the cumbersome equivalent of:

echo $(echo $(echo $(echo $(echo whatever))))

However note that in both versions, the command substitution is subject to word splitting. So, you'd want to quote them to prevent it.

With bash, dash, pdksh, yash, zsh, it's relatively easy:

echo "`echo "\`echo "\\\`echo "\\\\\\\`echo whatever\\\\\\\`"\\\`"\`"`"

With the Bourne or Korn shell, you also need to escape the " though, so that becomes:

echo "`echo \"\`echo \\\"\\\`echo \\\\\\\"\\\\\\\`echo whatever\\\\\\\`\\\\\\\"\\\`\\\"\`\"`"

Compare with:

echo "$(echo "$(echo "$(echo "$(echo whatever)")")")" 

Solution 2

This is interesting.

This expands to uh:

echo `echo \`echo uh\``

and not even

echo "`echo \`echo uh\``"

suppresses the inner expansion.

In both bash and POSIX shells (dash), you have $() as a nesting-friendly alternative to backticks.

Interestingly, the inner process substitution does not expand with $() regardless of whether it's quoted or not or whether the inner substitution uses backticks or $():

$ echo $(echo \$\(echo uh\))
  $(echo uh)
$ echo $(echo \`echo uh\`)
  `echo uh`

The implicit expansion with backticks doesn't look very safe. I'd stick to $(), especially if you want to nest.

Share:
6,779

Related videos on Youtube

viuser
Author by

viuser

Updated on September 18, 2022

Comments

  • viuser
    viuser almost 2 years
    test@debian:~$ echo `echo \`echo "uh!"\``
    uh!
    

    How does the Bash do that? It seems that it first executes the expression in the non-escaped backticks, which gives back (the double-quotes "" are removed, right?):

    `echo uh!`
    

    So we have an input equivalent to:

    test@debian:~$ echo `echo uh!`
    

    (side note: really, why does it work? Because:

    test@debian:~$ echo `echo uh!`
    -bash: !`: event not found
    

    )

    Then Bash executes the expression in backticks again, which gives:

    test@debian:~$ echo uh!
    

    Which finally gives us the output:

    uh!
    

    Is that right? And how could one encapsulate four echo-backtick-expression into each other?

    • roaima
      roaima over 8 years
      This is bash right? Why not use $( ... ) and dispense entirely with the horrible mess that is backtick nesting? echo $(echo $(echo "uh!"))
    • viuser
      viuser over 8 years
      @Pandya: You don't understand: I didn't forget it. It's what the bash, evaluating the outer backtick-expression, should give us.
    • roaima
      roaima over 8 years
      echo `echo 1 \`echo 2 \\\`echo 3 \\\\\\\`echo 4 "uh!" \\\\\\\` \\\` \` ` But I really would prefer echo $(echo 1 $(echo 2 $(echo 3 $(echo 4 "uh!" ) ) ) )
  • Wildcard
    Wildcard over 8 years
    tl;dr is: Use $(command) rather than backticks. +1 for the last sentence. :)