What is wrong with “echo $(stuff)†or “echo `stuff`â€�
Clash Royale CLAN TAG#URR8PPP
up vote
30
down vote
favorite
I used one of the following
echo $(stuff)
echo `stuff`
(where stuff
is e.g. pwd
or date
or something more complicated).
Then I was told this syntax is wrong, a bad practice, non-elegant, excessive, redundant, overly complicated, a cargo cult programming, noobish, naive etc.
But the command does work, so what exactly is wrong with it?
shell-script sh echo
 |Â
show 5 more comments
up vote
30
down vote
favorite
I used one of the following
echo $(stuff)
echo `stuff`
(where stuff
is e.g. pwd
or date
or something more complicated).
Then I was told this syntax is wrong, a bad practice, non-elegant, excessive, redundant, overly complicated, a cargo cult programming, noobish, naive etc.
But the command does work, so what exactly is wrong with it?
shell-script sh echo
10
It's redundant and therefore should not be used. Compare with Useless Use Of Cat: porkmail.org/era/unix/award.html
– dr01
Aug 28 at 8:20
7
echo $(echo $(echo $(echo$(echo $(stuff)))))
also does work, and still you probably wouldn't use it, right? ;-)
– Peter A. Schneider
Aug 29 at 7:57
1
What are you trying to do with that expansion, exactly?
– curiousguy
Aug 29 at 8:08
@curiousguy I'm trying to help other users, hence my answer below. Recently, I've seen at least three questions that use this syntax. Their authors were trying to do… variousstuff
. :D
– Kamil Maciorowski
Aug 29 at 8:15
2
Also, don't we all agree that it's unwise to confine oneself to an echo chamber?? ;-)
– Peter A. Schneider
Aug 29 at 8:24
 |Â
show 5 more comments
up vote
30
down vote
favorite
up vote
30
down vote
favorite
I used one of the following
echo $(stuff)
echo `stuff`
(where stuff
is e.g. pwd
or date
or something more complicated).
Then I was told this syntax is wrong, a bad practice, non-elegant, excessive, redundant, overly complicated, a cargo cult programming, noobish, naive etc.
But the command does work, so what exactly is wrong with it?
shell-script sh echo
I used one of the following
echo $(stuff)
echo `stuff`
(where stuff
is e.g. pwd
or date
or something more complicated).
Then I was told this syntax is wrong, a bad practice, non-elegant, excessive, redundant, overly complicated, a cargo cult programming, noobish, naive etc.
But the command does work, so what exactly is wrong with it?
shell-script sh echo
asked Aug 27 at 21:47
Kamil Maciorowski
19.1k134667
19.1k134667
10
It's redundant and therefore should not be used. Compare with Useless Use Of Cat: porkmail.org/era/unix/award.html
– dr01
Aug 28 at 8:20
7
echo $(echo $(echo $(echo$(echo $(stuff)))))
also does work, and still you probably wouldn't use it, right? ;-)
– Peter A. Schneider
Aug 29 at 7:57
1
What are you trying to do with that expansion, exactly?
– curiousguy
Aug 29 at 8:08
@curiousguy I'm trying to help other users, hence my answer below. Recently, I've seen at least three questions that use this syntax. Their authors were trying to do… variousstuff
. :D
– Kamil Maciorowski
Aug 29 at 8:15
2
Also, don't we all agree that it's unwise to confine oneself to an echo chamber?? ;-)
– Peter A. Schneider
Aug 29 at 8:24
 |Â
show 5 more comments
10
It's redundant and therefore should not be used. Compare with Useless Use Of Cat: porkmail.org/era/unix/award.html
– dr01
Aug 28 at 8:20
7
echo $(echo $(echo $(echo$(echo $(stuff)))))
also does work, and still you probably wouldn't use it, right? ;-)
– Peter A. Schneider
Aug 29 at 7:57
1
What are you trying to do with that expansion, exactly?
– curiousguy
Aug 29 at 8:08
@curiousguy I'm trying to help other users, hence my answer below. Recently, I've seen at least three questions that use this syntax. Their authors were trying to do… variousstuff
. :D
– Kamil Maciorowski
Aug 29 at 8:15
2
Also, don't we all agree that it's unwise to confine oneself to an echo chamber?? ;-)
– Peter A. Schneider
Aug 29 at 8:24
10
10
It's redundant and therefore should not be used. Compare with Useless Use Of Cat: porkmail.org/era/unix/award.html
– dr01
Aug 28 at 8:20
It's redundant and therefore should not be used. Compare with Useless Use Of Cat: porkmail.org/era/unix/award.html
– dr01
Aug 28 at 8:20
7
7
echo $(echo $(echo $(echo$(echo $(stuff)))))
also does work, and still you probably wouldn't use it, right? ;-)– Peter A. Schneider
Aug 29 at 7:57
echo $(echo $(echo $(echo$(echo $(stuff)))))
also does work, and still you probably wouldn't use it, right? ;-)– Peter A. Schneider
Aug 29 at 7:57
1
1
What are you trying to do with that expansion, exactly?
– curiousguy
Aug 29 at 8:08
What are you trying to do with that expansion, exactly?
– curiousguy
Aug 29 at 8:08
@curiousguy I'm trying to help other users, hence my answer below. Recently, I've seen at least three questions that use this syntax. Their authors were trying to do… various
stuff
. :D– Kamil Maciorowski
Aug 29 at 8:15
@curiousguy I'm trying to help other users, hence my answer below. Recently, I've seen at least three questions that use this syntax. Their authors were trying to do… various
stuff
. :D– Kamil Maciorowski
Aug 29 at 8:15
2
2
Also, don't we all agree that it's unwise to confine oneself to an echo chamber?? ;-)
– Peter A. Schneider
Aug 29 at 8:24
Also, don't we all agree that it's unwise to confine oneself to an echo chamber?? ;-)
– Peter A. Schneider
Aug 29 at 8:24
 |Â
show 5 more comments
2 Answers
2
active
oldest
votes
up vote
61
down vote
accepted
tl;dr
A sole stuff
would most probably work for you.
Full answer
What happens
When you run foo $(stuff)
, this is what happens:
stuff
runs;- its output (stdout), instead of being printed, replaces
$(stuff)
in the invocation offoo
; - then
foo
runs, its command line arguments obviously depend on whatstuff
returned.
This $(…)
mechanism is called "command substitution". In your case the main command is echo
which basically prints its command line arguments to stdout. So whatever stuff
tries to print to stdout is captured, passed to echo
and printed to stdout by echo
.
If you want the output of stuff
to be printed to stdout, just run the sole stuff
.
The `…`
syntax serves the same purpose as $(…)
(under the same name: "command substitution"), there are few differences though, so you cannot blindly interchange them. See this FAQ and this question.
Should I avoid echo $(stuff)
no matter what?
There is a reason you may want to use echo $(stuff)
if you know what you're doing. For the same reason you should avoid echo $(stuff)
if you don't really know what you're doing.
The point is stuff
and echo $(stuff)
are not exactly equivalent. The latter means calling split+glob operator on the output of stuff
with the default value of $IFS
. Double quoting the command substitution prevents this. Single quoting the command substitution makes it no longer be a command substitution.
To observe this when it comes to splitting run these commands:
echo "a b"
echo $(echo "a b")
echo "$(echo "a b")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "a b")'
And for globbing:
echo "/*"
echo $(echo "/*")
echo "$(echo "/*")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "/*")'
As you can see echo "$(stuff)"
is equivalent(-ish*) to stuff
. You could use it but what's the point of complicating things this way?
On the other hand if you want the output of stuff
to undergo splitting+globbing then you may find echo $(stuff)
useful. It has to be your conscious decision though.
There are commands generating output that should be evaluated (which includes splitting, globbing and more) and run by the shell, so eval "$(stuff)"
is a possibility (see this answer). I have never seen a command that needs its output to undergo additional splitting+globbing before being printed. Deliberately using echo $(stuff)
seems very uncommon.
What about var=$(stuff); echo "$var"
?
Good point. This snippet:
var=$(stuff)
echo "$var"
should be equivalent to echo "$(stuff)"
equivalent(-ish*) to stuff
. If it's the whole code, just run stuff
instead.
If, however, you need to use the output of stuff
more than once then this approach
var=$(stuff)
foo "$var"
bar "$var"
is usually better than
foo "$(stuff)"
bar "$(stuff)"
Even if foo
is echo
and you get echo "$var"
in your code, it may be better to keep it this way. Things to consider:
- With
var=$(stuff)
stuff
runs once; even if the command is fast, avoiding computing the same output twice is the right thing. Or maybestuff
has effects other than writing to stdout (e.g. creating a temporary file, starting a service, starting a virtual machine, notifying a remote server), so you don't want to run it multiple times. - If
stuff
generates time-depending or somewhat random output, you may get inconsistent results fromfoo "$(stuff)"
andbar "$(stuff)"
. Aftervar=$(stuff)
the value of$var
is fixed and you can be surefoo "$var"
andbar "$var"
get identical command line argument.
In some cases instead of foo "$var"
you may want (need) to use foo $var
, especially if stuff
generates multiple arguments for foo
(an array variable may be better if your shell supports it). Again, know what you're doing. When it comes to echo
the difference between echo $var
and echo "$var"
is the same as between echo $(stuff)
and echo "$(stuff)"
.
*Equivalent(-ish)?
I said echo "$(stuff)"
is equivalent(-ish) to stuff
. There are at least two issues that make it not exactly equivalent:
$(stuff)
runsstuff
in a subshell, so it's better to sayecho "$(stuff)"
is equivalent(-ish) to(stuff)
. Commands that affect the shell they run in, if in a subshell, don't affect the main shell.In this example
stuff
isa=1; echo "$a"
:a=0
echo "$(a=1; echo "$a")" # echo "$(stuff)"
echo "$a"Compare it with
a=0
a=1; echo "$a" # stuff
echo "$a"and with
a=0
(a=1; echo "$a") # (stuff)
echo "$a"Another example, start with
stuff
beingcd /; pwd
:cd /bin
echo "$(cd /; pwd)" # echo "$(stuff)"
pwdand test
stuff
and(stuff)
versions.echo
is not a good tool to display uncontrolled data. Thisecho "$var"
we were talking about should have beenprintf '%sn' "$var"
. But since the question mentionsecho
and since the most probable solution is not to useecho
in the first place, I decided not to introduceprintf
up until now.stuff
or(stuff)
will interleave stdout and stderr output, whileecho $(stuff)
will print all the stderr output fromstuff
(which runs first), and only then the stdout output digested byecho
(which runs last).$(…)
strips off any trailing newline and thenecho
adds it back. Soecho "$(printf %s 'a')" | xxd
gives different output thanprintf %s 'a' | xxd
.Some commands (
ls
for example) work differently depending if the standard output is a console or not; sols | cat
does not the samels
does. Similarlyecho $(ls)
will work differently thanls
.Putting
ls
aside, in a general case if you have to force this other behavior thenstuff | cat
is better thanecho $(ls)
orecho "$(ls)"
because it doesn't trigger all the other issues mentioned here.Possibly different exit status (mentioned for completeness of this wiki answer; for details see another answer that deserves credit).
5
One more difference: thestuff
way will interleavestdout
andstderr
output, whileecho `stuff`
will print all thestderr
output fromstuff
, and only then thestdout
output.
– Ruslan
Aug 28 at 5:55
3
And this is another example for: There can hardly be too many quotes in bash scripts.echo $(stuff)
can put you into far more troubles asecho "$(stuff)"
if you do not want globbing and expansion explicitly.
– rexkogitans
Aug 28 at 7:01
2
One more slight difference:$(…)
strips off any trailing newline and thenecho
adds it back. Soecho "$(printf %s 'a')" | xxd
gives different output thanprintf %s 'a' | xxd
.
– derobert
Aug 28 at 19:39
1
You should not forget that some commands (ls
for example) work differently depending if the standard output is a console or not; sols | cat
does not the samels
does. And of courseecho $(ls)
will work differently thanls
.
– Martin Rosenau
Aug 29 at 5:14
@Ruslan The answer is now community wiki. I have added your useful comment to the wiki. Thank you.
– Kamil Maciorowski
Aug 29 at 9:42
 |Â
show 2 more comments
up vote
4
down vote
Another difference: The sub-shell exit code is lost, so the exit code of echo
is retrieved instead.
> stuff() return 1
> stuff; echo $?
1
> echo $(stuff); echo $?
0
3
Welcome to Super User! Can you explain the difference you are demonstrating? Thanks
– bertieb
Aug 29 at 9:04
4
I believe that this shows that the return code$?
will be the return code ofecho
(forecho $(stuff)
) instead of the onereturn
ed bystuff
. Thestuff
functionreturn 1
(exit code), butecho
sets it to "0" regardless of the return code ofstuff
. Still should be in the answer.
– Ismael Miguel
Aug 29 at 9:32
the return value from the subshell has been lost
– phuclv
Aug 29 at 9:50
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
61
down vote
accepted
tl;dr
A sole stuff
would most probably work for you.
Full answer
What happens
When you run foo $(stuff)
, this is what happens:
stuff
runs;- its output (stdout), instead of being printed, replaces
$(stuff)
in the invocation offoo
; - then
foo
runs, its command line arguments obviously depend on whatstuff
returned.
This $(…)
mechanism is called "command substitution". In your case the main command is echo
which basically prints its command line arguments to stdout. So whatever stuff
tries to print to stdout is captured, passed to echo
and printed to stdout by echo
.
If you want the output of stuff
to be printed to stdout, just run the sole stuff
.
The `…`
syntax serves the same purpose as $(…)
(under the same name: "command substitution"), there are few differences though, so you cannot blindly interchange them. See this FAQ and this question.
Should I avoid echo $(stuff)
no matter what?
There is a reason you may want to use echo $(stuff)
if you know what you're doing. For the same reason you should avoid echo $(stuff)
if you don't really know what you're doing.
The point is stuff
and echo $(stuff)
are not exactly equivalent. The latter means calling split+glob operator on the output of stuff
with the default value of $IFS
. Double quoting the command substitution prevents this. Single quoting the command substitution makes it no longer be a command substitution.
To observe this when it comes to splitting run these commands:
echo "a b"
echo $(echo "a b")
echo "$(echo "a b")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "a b")'
And for globbing:
echo "/*"
echo $(echo "/*")
echo "$(echo "/*")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "/*")'
As you can see echo "$(stuff)"
is equivalent(-ish*) to stuff
. You could use it but what's the point of complicating things this way?
On the other hand if you want the output of stuff
to undergo splitting+globbing then you may find echo $(stuff)
useful. It has to be your conscious decision though.
There are commands generating output that should be evaluated (which includes splitting, globbing and more) and run by the shell, so eval "$(stuff)"
is a possibility (see this answer). I have never seen a command that needs its output to undergo additional splitting+globbing before being printed. Deliberately using echo $(stuff)
seems very uncommon.
What about var=$(stuff); echo "$var"
?
Good point. This snippet:
var=$(stuff)
echo "$var"
should be equivalent to echo "$(stuff)"
equivalent(-ish*) to stuff
. If it's the whole code, just run stuff
instead.
If, however, you need to use the output of stuff
more than once then this approach
var=$(stuff)
foo "$var"
bar "$var"
is usually better than
foo "$(stuff)"
bar "$(stuff)"
Even if foo
is echo
and you get echo "$var"
in your code, it may be better to keep it this way. Things to consider:
- With
var=$(stuff)
stuff
runs once; even if the command is fast, avoiding computing the same output twice is the right thing. Or maybestuff
has effects other than writing to stdout (e.g. creating a temporary file, starting a service, starting a virtual machine, notifying a remote server), so you don't want to run it multiple times. - If
stuff
generates time-depending or somewhat random output, you may get inconsistent results fromfoo "$(stuff)"
andbar "$(stuff)"
. Aftervar=$(stuff)
the value of$var
is fixed and you can be surefoo "$var"
andbar "$var"
get identical command line argument.
In some cases instead of foo "$var"
you may want (need) to use foo $var
, especially if stuff
generates multiple arguments for foo
(an array variable may be better if your shell supports it). Again, know what you're doing. When it comes to echo
the difference between echo $var
and echo "$var"
is the same as between echo $(stuff)
and echo "$(stuff)"
.
*Equivalent(-ish)?
I said echo "$(stuff)"
is equivalent(-ish) to stuff
. There are at least two issues that make it not exactly equivalent:
$(stuff)
runsstuff
in a subshell, so it's better to sayecho "$(stuff)"
is equivalent(-ish) to(stuff)
. Commands that affect the shell they run in, if in a subshell, don't affect the main shell.In this example
stuff
isa=1; echo "$a"
:a=0
echo "$(a=1; echo "$a")" # echo "$(stuff)"
echo "$a"Compare it with
a=0
a=1; echo "$a" # stuff
echo "$a"and with
a=0
(a=1; echo "$a") # (stuff)
echo "$a"Another example, start with
stuff
beingcd /; pwd
:cd /bin
echo "$(cd /; pwd)" # echo "$(stuff)"
pwdand test
stuff
and(stuff)
versions.echo
is not a good tool to display uncontrolled data. Thisecho "$var"
we were talking about should have beenprintf '%sn' "$var"
. But since the question mentionsecho
and since the most probable solution is not to useecho
in the first place, I decided not to introduceprintf
up until now.stuff
or(stuff)
will interleave stdout and stderr output, whileecho $(stuff)
will print all the stderr output fromstuff
(which runs first), and only then the stdout output digested byecho
(which runs last).$(…)
strips off any trailing newline and thenecho
adds it back. Soecho "$(printf %s 'a')" | xxd
gives different output thanprintf %s 'a' | xxd
.Some commands (
ls
for example) work differently depending if the standard output is a console or not; sols | cat
does not the samels
does. Similarlyecho $(ls)
will work differently thanls
.Putting
ls
aside, in a general case if you have to force this other behavior thenstuff | cat
is better thanecho $(ls)
orecho "$(ls)"
because it doesn't trigger all the other issues mentioned here.Possibly different exit status (mentioned for completeness of this wiki answer; for details see another answer that deserves credit).
5
One more difference: thestuff
way will interleavestdout
andstderr
output, whileecho `stuff`
will print all thestderr
output fromstuff
, and only then thestdout
output.
– Ruslan
Aug 28 at 5:55
3
And this is another example for: There can hardly be too many quotes in bash scripts.echo $(stuff)
can put you into far more troubles asecho "$(stuff)"
if you do not want globbing and expansion explicitly.
– rexkogitans
Aug 28 at 7:01
2
One more slight difference:$(…)
strips off any trailing newline and thenecho
adds it back. Soecho "$(printf %s 'a')" | xxd
gives different output thanprintf %s 'a' | xxd
.
– derobert
Aug 28 at 19:39
1
You should not forget that some commands (ls
for example) work differently depending if the standard output is a console or not; sols | cat
does not the samels
does. And of courseecho $(ls)
will work differently thanls
.
– Martin Rosenau
Aug 29 at 5:14
@Ruslan The answer is now community wiki. I have added your useful comment to the wiki. Thank you.
– Kamil Maciorowski
Aug 29 at 9:42
 |Â
show 2 more comments
up vote
61
down vote
accepted
tl;dr
A sole stuff
would most probably work for you.
Full answer
What happens
When you run foo $(stuff)
, this is what happens:
stuff
runs;- its output (stdout), instead of being printed, replaces
$(stuff)
in the invocation offoo
; - then
foo
runs, its command line arguments obviously depend on whatstuff
returned.
This $(…)
mechanism is called "command substitution". In your case the main command is echo
which basically prints its command line arguments to stdout. So whatever stuff
tries to print to stdout is captured, passed to echo
and printed to stdout by echo
.
If you want the output of stuff
to be printed to stdout, just run the sole stuff
.
The `…`
syntax serves the same purpose as $(…)
(under the same name: "command substitution"), there are few differences though, so you cannot blindly interchange them. See this FAQ and this question.
Should I avoid echo $(stuff)
no matter what?
There is a reason you may want to use echo $(stuff)
if you know what you're doing. For the same reason you should avoid echo $(stuff)
if you don't really know what you're doing.
The point is stuff
and echo $(stuff)
are not exactly equivalent. The latter means calling split+glob operator on the output of stuff
with the default value of $IFS
. Double quoting the command substitution prevents this. Single quoting the command substitution makes it no longer be a command substitution.
To observe this when it comes to splitting run these commands:
echo "a b"
echo $(echo "a b")
echo "$(echo "a b")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "a b")'
And for globbing:
echo "/*"
echo $(echo "/*")
echo "$(echo "/*")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "/*")'
As you can see echo "$(stuff)"
is equivalent(-ish*) to stuff
. You could use it but what's the point of complicating things this way?
On the other hand if you want the output of stuff
to undergo splitting+globbing then you may find echo $(stuff)
useful. It has to be your conscious decision though.
There are commands generating output that should be evaluated (which includes splitting, globbing and more) and run by the shell, so eval "$(stuff)"
is a possibility (see this answer). I have never seen a command that needs its output to undergo additional splitting+globbing before being printed. Deliberately using echo $(stuff)
seems very uncommon.
What about var=$(stuff); echo "$var"
?
Good point. This snippet:
var=$(stuff)
echo "$var"
should be equivalent to echo "$(stuff)"
equivalent(-ish*) to stuff
. If it's the whole code, just run stuff
instead.
If, however, you need to use the output of stuff
more than once then this approach
var=$(stuff)
foo "$var"
bar "$var"
is usually better than
foo "$(stuff)"
bar "$(stuff)"
Even if foo
is echo
and you get echo "$var"
in your code, it may be better to keep it this way. Things to consider:
- With
var=$(stuff)
stuff
runs once; even if the command is fast, avoiding computing the same output twice is the right thing. Or maybestuff
has effects other than writing to stdout (e.g. creating a temporary file, starting a service, starting a virtual machine, notifying a remote server), so you don't want to run it multiple times. - If
stuff
generates time-depending or somewhat random output, you may get inconsistent results fromfoo "$(stuff)"
andbar "$(stuff)"
. Aftervar=$(stuff)
the value of$var
is fixed and you can be surefoo "$var"
andbar "$var"
get identical command line argument.
In some cases instead of foo "$var"
you may want (need) to use foo $var
, especially if stuff
generates multiple arguments for foo
(an array variable may be better if your shell supports it). Again, know what you're doing. When it comes to echo
the difference between echo $var
and echo "$var"
is the same as between echo $(stuff)
and echo "$(stuff)"
.
*Equivalent(-ish)?
I said echo "$(stuff)"
is equivalent(-ish) to stuff
. There are at least two issues that make it not exactly equivalent:
$(stuff)
runsstuff
in a subshell, so it's better to sayecho "$(stuff)"
is equivalent(-ish) to(stuff)
. Commands that affect the shell they run in, if in a subshell, don't affect the main shell.In this example
stuff
isa=1; echo "$a"
:a=0
echo "$(a=1; echo "$a")" # echo "$(stuff)"
echo "$a"Compare it with
a=0
a=1; echo "$a" # stuff
echo "$a"and with
a=0
(a=1; echo "$a") # (stuff)
echo "$a"Another example, start with
stuff
beingcd /; pwd
:cd /bin
echo "$(cd /; pwd)" # echo "$(stuff)"
pwdand test
stuff
and(stuff)
versions.echo
is not a good tool to display uncontrolled data. Thisecho "$var"
we were talking about should have beenprintf '%sn' "$var"
. But since the question mentionsecho
and since the most probable solution is not to useecho
in the first place, I decided not to introduceprintf
up until now.stuff
or(stuff)
will interleave stdout and stderr output, whileecho $(stuff)
will print all the stderr output fromstuff
(which runs first), and only then the stdout output digested byecho
(which runs last).$(…)
strips off any trailing newline and thenecho
adds it back. Soecho "$(printf %s 'a')" | xxd
gives different output thanprintf %s 'a' | xxd
.Some commands (
ls
for example) work differently depending if the standard output is a console or not; sols | cat
does not the samels
does. Similarlyecho $(ls)
will work differently thanls
.Putting
ls
aside, in a general case if you have to force this other behavior thenstuff | cat
is better thanecho $(ls)
orecho "$(ls)"
because it doesn't trigger all the other issues mentioned here.Possibly different exit status (mentioned for completeness of this wiki answer; for details see another answer that deserves credit).
5
One more difference: thestuff
way will interleavestdout
andstderr
output, whileecho `stuff`
will print all thestderr
output fromstuff
, and only then thestdout
output.
– Ruslan
Aug 28 at 5:55
3
And this is another example for: There can hardly be too many quotes in bash scripts.echo $(stuff)
can put you into far more troubles asecho "$(stuff)"
if you do not want globbing and expansion explicitly.
– rexkogitans
Aug 28 at 7:01
2
One more slight difference:$(…)
strips off any trailing newline and thenecho
adds it back. Soecho "$(printf %s 'a')" | xxd
gives different output thanprintf %s 'a' | xxd
.
– derobert
Aug 28 at 19:39
1
You should not forget that some commands (ls
for example) work differently depending if the standard output is a console or not; sols | cat
does not the samels
does. And of courseecho $(ls)
will work differently thanls
.
– Martin Rosenau
Aug 29 at 5:14
@Ruslan The answer is now community wiki. I have added your useful comment to the wiki. Thank you.
– Kamil Maciorowski
Aug 29 at 9:42
 |Â
show 2 more comments
up vote
61
down vote
accepted
up vote
61
down vote
accepted
tl;dr
A sole stuff
would most probably work for you.
Full answer
What happens
When you run foo $(stuff)
, this is what happens:
stuff
runs;- its output (stdout), instead of being printed, replaces
$(stuff)
in the invocation offoo
; - then
foo
runs, its command line arguments obviously depend on whatstuff
returned.
This $(…)
mechanism is called "command substitution". In your case the main command is echo
which basically prints its command line arguments to stdout. So whatever stuff
tries to print to stdout is captured, passed to echo
and printed to stdout by echo
.
If you want the output of stuff
to be printed to stdout, just run the sole stuff
.
The `…`
syntax serves the same purpose as $(…)
(under the same name: "command substitution"), there are few differences though, so you cannot blindly interchange them. See this FAQ and this question.
Should I avoid echo $(stuff)
no matter what?
There is a reason you may want to use echo $(stuff)
if you know what you're doing. For the same reason you should avoid echo $(stuff)
if you don't really know what you're doing.
The point is stuff
and echo $(stuff)
are not exactly equivalent. The latter means calling split+glob operator on the output of stuff
with the default value of $IFS
. Double quoting the command substitution prevents this. Single quoting the command substitution makes it no longer be a command substitution.
To observe this when it comes to splitting run these commands:
echo "a b"
echo $(echo "a b")
echo "$(echo "a b")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "a b")'
And for globbing:
echo "/*"
echo $(echo "/*")
echo "$(echo "/*")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "/*")'
As you can see echo "$(stuff)"
is equivalent(-ish*) to stuff
. You could use it but what's the point of complicating things this way?
On the other hand if you want the output of stuff
to undergo splitting+globbing then you may find echo $(stuff)
useful. It has to be your conscious decision though.
There are commands generating output that should be evaluated (which includes splitting, globbing and more) and run by the shell, so eval "$(stuff)"
is a possibility (see this answer). I have never seen a command that needs its output to undergo additional splitting+globbing before being printed. Deliberately using echo $(stuff)
seems very uncommon.
What about var=$(stuff); echo "$var"
?
Good point. This snippet:
var=$(stuff)
echo "$var"
should be equivalent to echo "$(stuff)"
equivalent(-ish*) to stuff
. If it's the whole code, just run stuff
instead.
If, however, you need to use the output of stuff
more than once then this approach
var=$(stuff)
foo "$var"
bar "$var"
is usually better than
foo "$(stuff)"
bar "$(stuff)"
Even if foo
is echo
and you get echo "$var"
in your code, it may be better to keep it this way. Things to consider:
- With
var=$(stuff)
stuff
runs once; even if the command is fast, avoiding computing the same output twice is the right thing. Or maybestuff
has effects other than writing to stdout (e.g. creating a temporary file, starting a service, starting a virtual machine, notifying a remote server), so you don't want to run it multiple times. - If
stuff
generates time-depending or somewhat random output, you may get inconsistent results fromfoo "$(stuff)"
andbar "$(stuff)"
. Aftervar=$(stuff)
the value of$var
is fixed and you can be surefoo "$var"
andbar "$var"
get identical command line argument.
In some cases instead of foo "$var"
you may want (need) to use foo $var
, especially if stuff
generates multiple arguments for foo
(an array variable may be better if your shell supports it). Again, know what you're doing. When it comes to echo
the difference between echo $var
and echo "$var"
is the same as between echo $(stuff)
and echo "$(stuff)"
.
*Equivalent(-ish)?
I said echo "$(stuff)"
is equivalent(-ish) to stuff
. There are at least two issues that make it not exactly equivalent:
$(stuff)
runsstuff
in a subshell, so it's better to sayecho "$(stuff)"
is equivalent(-ish) to(stuff)
. Commands that affect the shell they run in, if in a subshell, don't affect the main shell.In this example
stuff
isa=1; echo "$a"
:a=0
echo "$(a=1; echo "$a")" # echo "$(stuff)"
echo "$a"Compare it with
a=0
a=1; echo "$a" # stuff
echo "$a"and with
a=0
(a=1; echo "$a") # (stuff)
echo "$a"Another example, start with
stuff
beingcd /; pwd
:cd /bin
echo "$(cd /; pwd)" # echo "$(stuff)"
pwdand test
stuff
and(stuff)
versions.echo
is not a good tool to display uncontrolled data. Thisecho "$var"
we were talking about should have beenprintf '%sn' "$var"
. But since the question mentionsecho
and since the most probable solution is not to useecho
in the first place, I decided not to introduceprintf
up until now.stuff
or(stuff)
will interleave stdout and stderr output, whileecho $(stuff)
will print all the stderr output fromstuff
(which runs first), and only then the stdout output digested byecho
(which runs last).$(…)
strips off any trailing newline and thenecho
adds it back. Soecho "$(printf %s 'a')" | xxd
gives different output thanprintf %s 'a' | xxd
.Some commands (
ls
for example) work differently depending if the standard output is a console or not; sols | cat
does not the samels
does. Similarlyecho $(ls)
will work differently thanls
.Putting
ls
aside, in a general case if you have to force this other behavior thenstuff | cat
is better thanecho $(ls)
orecho "$(ls)"
because it doesn't trigger all the other issues mentioned here.Possibly different exit status (mentioned for completeness of this wiki answer; for details see another answer that deserves credit).
tl;dr
A sole stuff
would most probably work for you.
Full answer
What happens
When you run foo $(stuff)
, this is what happens:
stuff
runs;- its output (stdout), instead of being printed, replaces
$(stuff)
in the invocation offoo
; - then
foo
runs, its command line arguments obviously depend on whatstuff
returned.
This $(…)
mechanism is called "command substitution". In your case the main command is echo
which basically prints its command line arguments to stdout. So whatever stuff
tries to print to stdout is captured, passed to echo
and printed to stdout by echo
.
If you want the output of stuff
to be printed to stdout, just run the sole stuff
.
The `…`
syntax serves the same purpose as $(…)
(under the same name: "command substitution"), there are few differences though, so you cannot blindly interchange them. See this FAQ and this question.
Should I avoid echo $(stuff)
no matter what?
There is a reason you may want to use echo $(stuff)
if you know what you're doing. For the same reason you should avoid echo $(stuff)
if you don't really know what you're doing.
The point is stuff
and echo $(stuff)
are not exactly equivalent. The latter means calling split+glob operator on the output of stuff
with the default value of $IFS
. Double quoting the command substitution prevents this. Single quoting the command substitution makes it no longer be a command substitution.
To observe this when it comes to splitting run these commands:
echo "a b"
echo $(echo "a b")
echo "$(echo "a b")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "a b")'
And for globbing:
echo "/*"
echo $(echo "/*")
echo "$(echo "/*")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "/*")'
As you can see echo "$(stuff)"
is equivalent(-ish*) to stuff
. You could use it but what's the point of complicating things this way?
On the other hand if you want the output of stuff
to undergo splitting+globbing then you may find echo $(stuff)
useful. It has to be your conscious decision though.
There are commands generating output that should be evaluated (which includes splitting, globbing and more) and run by the shell, so eval "$(stuff)"
is a possibility (see this answer). I have never seen a command that needs its output to undergo additional splitting+globbing before being printed. Deliberately using echo $(stuff)
seems very uncommon.
What about var=$(stuff); echo "$var"
?
Good point. This snippet:
var=$(stuff)
echo "$var"
should be equivalent to echo "$(stuff)"
equivalent(-ish*) to stuff
. If it's the whole code, just run stuff
instead.
If, however, you need to use the output of stuff
more than once then this approach
var=$(stuff)
foo "$var"
bar "$var"
is usually better than
foo "$(stuff)"
bar "$(stuff)"
Even if foo
is echo
and you get echo "$var"
in your code, it may be better to keep it this way. Things to consider:
- With
var=$(stuff)
stuff
runs once; even if the command is fast, avoiding computing the same output twice is the right thing. Or maybestuff
has effects other than writing to stdout (e.g. creating a temporary file, starting a service, starting a virtual machine, notifying a remote server), so you don't want to run it multiple times. - If
stuff
generates time-depending or somewhat random output, you may get inconsistent results fromfoo "$(stuff)"
andbar "$(stuff)"
. Aftervar=$(stuff)
the value of$var
is fixed and you can be surefoo "$var"
andbar "$var"
get identical command line argument.
In some cases instead of foo "$var"
you may want (need) to use foo $var
, especially if stuff
generates multiple arguments for foo
(an array variable may be better if your shell supports it). Again, know what you're doing. When it comes to echo
the difference between echo $var
and echo "$var"
is the same as between echo $(stuff)
and echo "$(stuff)"
.
*Equivalent(-ish)?
I said echo "$(stuff)"
is equivalent(-ish) to stuff
. There are at least two issues that make it not exactly equivalent:
$(stuff)
runsstuff
in a subshell, so it's better to sayecho "$(stuff)"
is equivalent(-ish) to(stuff)
. Commands that affect the shell they run in, if in a subshell, don't affect the main shell.In this example
stuff
isa=1; echo "$a"
:a=0
echo "$(a=1; echo "$a")" # echo "$(stuff)"
echo "$a"Compare it with
a=0
a=1; echo "$a" # stuff
echo "$a"and with
a=0
(a=1; echo "$a") # (stuff)
echo "$a"Another example, start with
stuff
beingcd /; pwd
:cd /bin
echo "$(cd /; pwd)" # echo "$(stuff)"
pwdand test
stuff
and(stuff)
versions.echo
is not a good tool to display uncontrolled data. Thisecho "$var"
we were talking about should have beenprintf '%sn' "$var"
. But since the question mentionsecho
and since the most probable solution is not to useecho
in the first place, I decided not to introduceprintf
up until now.stuff
or(stuff)
will interleave stdout and stderr output, whileecho $(stuff)
will print all the stderr output fromstuff
(which runs first), and only then the stdout output digested byecho
(which runs last).$(…)
strips off any trailing newline and thenecho
adds it back. Soecho "$(printf %s 'a')" | xxd
gives different output thanprintf %s 'a' | xxd
.Some commands (
ls
for example) work differently depending if the standard output is a console or not; sols | cat
does not the samels
does. Similarlyecho $(ls)
will work differently thanls
.Putting
ls
aside, in a general case if you have to force this other behavior thenstuff | cat
is better thanecho $(ls)
orecho "$(ls)"
because it doesn't trigger all the other issues mentioned here.Possibly different exit status (mentioned for completeness of this wiki answer; for details see another answer that deserves credit).
edited Aug 29 at 9:41
community wiki
3 revs
Kamil Maciorowski
5
One more difference: thestuff
way will interleavestdout
andstderr
output, whileecho `stuff`
will print all thestderr
output fromstuff
, and only then thestdout
output.
– Ruslan
Aug 28 at 5:55
3
And this is another example for: There can hardly be too many quotes in bash scripts.echo $(stuff)
can put you into far more troubles asecho "$(stuff)"
if you do not want globbing and expansion explicitly.
– rexkogitans
Aug 28 at 7:01
2
One more slight difference:$(…)
strips off any trailing newline and thenecho
adds it back. Soecho "$(printf %s 'a')" | xxd
gives different output thanprintf %s 'a' | xxd
.
– derobert
Aug 28 at 19:39
1
You should not forget that some commands (ls
for example) work differently depending if the standard output is a console or not; sols | cat
does not the samels
does. And of courseecho $(ls)
will work differently thanls
.
– Martin Rosenau
Aug 29 at 5:14
@Ruslan The answer is now community wiki. I have added your useful comment to the wiki. Thank you.
– Kamil Maciorowski
Aug 29 at 9:42
 |Â
show 2 more comments
5
One more difference: thestuff
way will interleavestdout
andstderr
output, whileecho `stuff`
will print all thestderr
output fromstuff
, and only then thestdout
output.
– Ruslan
Aug 28 at 5:55
3
And this is another example for: There can hardly be too many quotes in bash scripts.echo $(stuff)
can put you into far more troubles asecho "$(stuff)"
if you do not want globbing and expansion explicitly.
– rexkogitans
Aug 28 at 7:01
2
One more slight difference:$(…)
strips off any trailing newline and thenecho
adds it back. Soecho "$(printf %s 'a')" | xxd
gives different output thanprintf %s 'a' | xxd
.
– derobert
Aug 28 at 19:39
1
You should not forget that some commands (ls
for example) work differently depending if the standard output is a console or not; sols | cat
does not the samels
does. And of courseecho $(ls)
will work differently thanls
.
– Martin Rosenau
Aug 29 at 5:14
@Ruslan The answer is now community wiki. I have added your useful comment to the wiki. Thank you.
– Kamil Maciorowski
Aug 29 at 9:42
5
5
One more difference: the
stuff
way will interleave stdout
and stderr
output, while echo `stuff`
will print all the stderr
output from stuff
, and only then the stdout
output.– Ruslan
Aug 28 at 5:55
One more difference: the
stuff
way will interleave stdout
and stderr
output, while echo `stuff`
will print all the stderr
output from stuff
, and only then the stdout
output.– Ruslan
Aug 28 at 5:55
3
3
And this is another example for: There can hardly be too many quotes in bash scripts.
echo $(stuff)
can put you into far more troubles as echo "$(stuff)"
if you do not want globbing and expansion explicitly.– rexkogitans
Aug 28 at 7:01
And this is another example for: There can hardly be too many quotes in bash scripts.
echo $(stuff)
can put you into far more troubles as echo "$(stuff)"
if you do not want globbing and expansion explicitly.– rexkogitans
Aug 28 at 7:01
2
2
One more slight difference:
$(…)
strips off any trailing newline and then echo
adds it back. So echo "$(printf %s 'a')" | xxd
gives different output than printf %s 'a' | xxd
.– derobert
Aug 28 at 19:39
One more slight difference:
$(…)
strips off any trailing newline and then echo
adds it back. So echo "$(printf %s 'a')" | xxd
gives different output than printf %s 'a' | xxd
.– derobert
Aug 28 at 19:39
1
1
You should not forget that some commands (
ls
for example) work differently depending if the standard output is a console or not; so ls | cat
does not the same ls
does. And of course echo $(ls)
will work differently than ls
.– Martin Rosenau
Aug 29 at 5:14
You should not forget that some commands (
ls
for example) work differently depending if the standard output is a console or not; so ls | cat
does not the same ls
does. And of course echo $(ls)
will work differently than ls
.– Martin Rosenau
Aug 29 at 5:14
@Ruslan The answer is now community wiki. I have added your useful comment to the wiki. Thank you.
– Kamil Maciorowski
Aug 29 at 9:42
@Ruslan The answer is now community wiki. I have added your useful comment to the wiki. Thank you.
– Kamil Maciorowski
Aug 29 at 9:42
 |Â
show 2 more comments
up vote
4
down vote
Another difference: The sub-shell exit code is lost, so the exit code of echo
is retrieved instead.
> stuff() return 1
> stuff; echo $?
1
> echo $(stuff); echo $?
0
3
Welcome to Super User! Can you explain the difference you are demonstrating? Thanks
– bertieb
Aug 29 at 9:04
4
I believe that this shows that the return code$?
will be the return code ofecho
(forecho $(stuff)
) instead of the onereturn
ed bystuff
. Thestuff
functionreturn 1
(exit code), butecho
sets it to "0" regardless of the return code ofstuff
. Still should be in the answer.
– Ismael Miguel
Aug 29 at 9:32
the return value from the subshell has been lost
– phuclv
Aug 29 at 9:50
add a comment |Â
up vote
4
down vote
Another difference: The sub-shell exit code is lost, so the exit code of echo
is retrieved instead.
> stuff() return 1
> stuff; echo $?
1
> echo $(stuff); echo $?
0
3
Welcome to Super User! Can you explain the difference you are demonstrating? Thanks
– bertieb
Aug 29 at 9:04
4
I believe that this shows that the return code$?
will be the return code ofecho
(forecho $(stuff)
) instead of the onereturn
ed bystuff
. Thestuff
functionreturn 1
(exit code), butecho
sets it to "0" regardless of the return code ofstuff
. Still should be in the answer.
– Ismael Miguel
Aug 29 at 9:32
the return value from the subshell has been lost
– phuclv
Aug 29 at 9:50
add a comment |Â
up vote
4
down vote
up vote
4
down vote
Another difference: The sub-shell exit code is lost, so the exit code of echo
is retrieved instead.
> stuff() return 1
> stuff; echo $?
1
> echo $(stuff); echo $?
0
Another difference: The sub-shell exit code is lost, so the exit code of echo
is retrieved instead.
> stuff() return 1
> stuff; echo $?
1
> echo $(stuff); echo $?
0
edited Aug 29 at 11:00
answered Aug 29 at 8:59
WaffleSouffle
1413
1413
3
Welcome to Super User! Can you explain the difference you are demonstrating? Thanks
– bertieb
Aug 29 at 9:04
4
I believe that this shows that the return code$?
will be the return code ofecho
(forecho $(stuff)
) instead of the onereturn
ed bystuff
. Thestuff
functionreturn 1
(exit code), butecho
sets it to "0" regardless of the return code ofstuff
. Still should be in the answer.
– Ismael Miguel
Aug 29 at 9:32
the return value from the subshell has been lost
– phuclv
Aug 29 at 9:50
add a comment |Â
3
Welcome to Super User! Can you explain the difference you are demonstrating? Thanks
– bertieb
Aug 29 at 9:04
4
I believe that this shows that the return code$?
will be the return code ofecho
(forecho $(stuff)
) instead of the onereturn
ed bystuff
. Thestuff
functionreturn 1
(exit code), butecho
sets it to "0" regardless of the return code ofstuff
. Still should be in the answer.
– Ismael Miguel
Aug 29 at 9:32
the return value from the subshell has been lost
– phuclv
Aug 29 at 9:50
3
3
Welcome to Super User! Can you explain the difference you are demonstrating? Thanks
– bertieb
Aug 29 at 9:04
Welcome to Super User! Can you explain the difference you are demonstrating? Thanks
– bertieb
Aug 29 at 9:04
4
4
I believe that this shows that the return code
$?
will be the return code of echo
(for echo $(stuff)
) instead of the one return
ed by stuff
. The stuff
function return 1
(exit code), but echo
sets it to "0" regardless of the return code of stuff
. Still should be in the answer.– Ismael Miguel
Aug 29 at 9:32
I believe that this shows that the return code
$?
will be the return code of echo
(for echo $(stuff)
) instead of the one return
ed by stuff
. The stuff
function return 1
(exit code), but echo
sets it to "0" regardless of the return code of stuff
. Still should be in the answer.– Ismael Miguel
Aug 29 at 9:32
the return value from the subshell has been lost
– phuclv
Aug 29 at 9:50
the return value from the subshell has been lost
– phuclv
Aug 29 at 9:50
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsuperuser.com%2fquestions%2f1352850%2fwhat-is-wrong-with-echo-stuff-or-echo-stuff%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
10
It's redundant and therefore should not be used. Compare with Useless Use Of Cat: porkmail.org/era/unix/award.html
– dr01
Aug 28 at 8:20
7
echo $(echo $(echo $(echo$(echo $(stuff)))))
also does work, and still you probably wouldn't use it, right? ;-)– Peter A. Schneider
Aug 29 at 7:57
1
What are you trying to do with that expansion, exactly?
– curiousguy
Aug 29 at 8:08
@curiousguy I'm trying to help other users, hence my answer below. Recently, I've seen at least three questions that use this syntax. Their authors were trying to do… various
stuff
. :D– Kamil Maciorowski
Aug 29 at 8:15
2
Also, don't we all agree that it's unwise to confine oneself to an echo chamber?? ;-)
– Peter A. Schneider
Aug 29 at 8:24