Suuuehgi
Suuuehgi

Reputation: 4990

Different output of command substitution

Why does adding | wc -l alters the result as in the following?

tst:

#!/bin/bash
pgrep tst | wc -l
echo $(pgrep tst | wc -l)
echo $(pgrep tst) | wc -l
$ ./tst
1
2
1

and even

$ bash -x tst
+ wc -l
+ pgrep tst
0
++ pgrep tst
++ wc -l
+ echo 0
0
++ pgrep tst
+ echo

Upvotes: 0

Views: 53

Answers (2)

Gordon Davisson
Gordon Davisson

Reputation: 125748

pgrep and subshells can have weird interactions, but in this case that's just a red herring; the actual cause is missing double-quotes around the command substitution:

$ cat tst2
#!/bin/bash
pgrep tst | wc -l
echo "$(pgrep tst | wc -l)"
echo "$(pgrep tst)" | wc -l
$ ./tst2
1
2
2

What's going on in the original script is that in the command

echo $(pgrep tst) | wc -l

pgrep prints two process IDs (the main shell running the script, and a subshell created to handle the echo part of the pipeline). It prints each one as a separate line, something like:

11730
11736

The command substitution captures that, but since it's not in double-quotes the newline between them gets converted to an argument break, so the whole thing becomes equivalent to:

echo 11730 11736 | wc -l

As a result, echo prints both IDs as a single line, and wc -l correctly reports that.

Upvotes: 1

chepner
chepner

Reputation: 530980

The command substitution induces an additional process that has tst in its name, which is included in the input to wc -l.

Upvotes: 1

Related Questions