100

Either I missed some backlash or backlashing does not seem to work with too much programmer-quote-looping.

$ echo "hello1-`echo hello2-\`echo hello3-\`echo hello4\`\``"

hello1-hello2-hello3-echo hello4

Wanted

hello1-hello2-hello3-hello4-hello5-hello6-...
Rahil Wazir
  • 10,007
  • 11
  • 42
  • 64
hhh
  • 50,788
  • 62
  • 179
  • 282

6 Answers6

166

Use $(commands) instead:

$ echo "hello1-$(echo hello2-$(echo hello3-$(echo hello4)))"
hello1-hello2-hello3-hello4

$(commands) does the same thing as backticks, but you can nest them.

You may also be interested in Bash range expansions:

echo hello{1..10}
hello1 hello2 hello3 hello4 hello5 hello6 hello7 hello8 hello9 hello10
Joey Adams
  • 41,996
  • 18
  • 86
  • 115
  • +1 like the {1..10}. Limit it with array? ZSH can "${$( date )[2,4]}". Why not: "echo ${echo hello1-$(echo hello2)[1]}"? – hhh Apr 17 '10 at 11:03
  • not all shells support `$()` – CervEd Dec 13 '21 at 16:53
  • @CervEd Just curious, what system and shell were you using? On Ubuntu, even the default "sh" (dash) supports the dollar notation and nesting it. – Joey Adams Dec 15 '21 at 17:29
  • 1
    @JoeyAdams I use shells that support `$()` and AFAIK most shells support it, but not all. [Solaris](https://docs.oracle.com/cd/E26502_01/html/E29030/sh-1.html#scrolltoc) `sh` doesn't seem to. – CervEd Dec 16 '21 at 11:20
38

if you insist to use backticks, following could be done

$ echo "hello1-`echo hello2-\`echo hello3-\\\`echo hello4\\\`\``"

you have to put backslashes, \\ \\\\ \\\\\\\\ by 2x and so on, its just very ugly, use $(commands) as other suggested.

YOU
  • 120,166
  • 34
  • 186
  • 219
12

Any time you want to evaluate a command use command substitution:

$(command)

Any time you want to evaluate an arithmetic expression use expression substitution:

$((expr))

You can nest these like this:

Let's say file1.txt is 30 lines long and file2.txt is 10 lines long, than you can evaluate an expression like this:

$(( $(wc -l file1.txt) - $(wc -l file2.txt) ))

which would output 20 ( the difference in number of lines between two files).

Etienne Lawlor
  • 6,817
  • 18
  • 77
  • 89
10

It's a lot easier if you use bash's $(cmd) command substitution syntax, which is much more friendly to being nested:

$ echo "hello1-$(echo hello2-$(echo hello3-$(echo hello4)))"
hello1-hello2-hello3-hello4
Mark Rushakoff
  • 249,864
  • 45
  • 407
  • 398
  • 5
    This is not restricted to *bash*. It is available in all shells that conform to POSIX 1003.1 (“POSIX shells”) and most Bourne-derived shell (*ksh*, *ash*, *dash*, *bash*, *zsh*, etc.) though not the actual Bourne shell (i.e. http://heirloom.sourceforge.net/sh.html ). – Chris Johnsen Apr 17 '10 at 03:02
  • wow, timestamp on this answer is IDENTICAL to that on @joey_adams answer! Synchronisity in it's most literal meaning :) Upvoting here too (: – drevicko May 08 '20 at 02:03
4

Sometimes backtick nesting can be substituted with xargs and pipes

$ echo hello4 | xargs echo hello3 | xargs echo hello2 | xargs echo hello1
hello1 hello2 hello3 hello4

Drawback of this solution are:

  • All arguments must be provided in reverse order (4→1);
  • All arguments become space separated (solvable with tr):

    $ echo hello4 | xargs echo hello3 | xargs echo hello2 | xargs echo hello1 | tr ' ' '-'
    hello1-hello2-hello3-hello4
    


Let's show a real use-case.

Following commands work in bash, but not in tcsh (backtick nesting is not handled very good in tcsh)

$ ls $(dirname $(which bash))
$ ls `dirname \`which bash\``

They can be substituted with

$ which bash | xargs dirname | xargs ls
G. C.
  • 387
  • 2
  • 6
0

You can capture and combine into a variable incrementally

__=`printf hello2-`
__=`printf "${__}hello3-"`
__=`printf "${__}hello4-"`
printf "hello1-${__}"
CervEd
  • 3,306
  • 28
  • 25