I am currently trying to make a script that creates bytes that will be piped as input to netcat.

Here is the idea of the script:

(perl -e "print \"$BYTES\x00\";

cat file;

perl -e "print \"More bytes\"x16 . \"\r\n\"";) | netcat ip port

I tried using both using a subshell and command substitution (ex. with $()) to execute the commands. However I fail to understand why the output of the script when using command substitution is wrong. I suspect that command substitution incorrectly pipes its output when executing multiple commands. Can someone explain to me why this is so?


Here is the variant that used command substitution:

$(perl -e "print \"$BYTES\x00\";

cat file;

perl -e "print \"More bytes\"x16 . \"\r\n\"";) | netcat ip port
  • 2
    Command substitution is replaced by it's output. That is, the output of that command in substitution form will not be piped into netcat because it will just be bare text. If you, for example, added echo before the command substitution starts, you may find that it works.
    – HalosGhost
    Commented Jul 2, 2015 at 13:18
  • @HalosGhost So you mean to say that the hex bytes I tried to generate became text in ascii form? I tried to do a hexdump of the outputs and what confuses me is the output from the command substitution contains an HTML document and the hex bytes i generated seems to be inside it.
    – MykelXIII
    Commented Jul 2, 2015 at 13:25
  • No, I mean, that you can think of any command inside a command substitution as being equivalent to typing the output of that command. Which means, in your second example, the result is just bare text. So, nothing is piped into netcat because nothing is run.
    – HalosGhost
    Commented Jul 2, 2015 at 13:30
  • @HalosGhost I see. So the output of command substitution is same as typing in stdin causing nothing to be piped am I correct? I am new to scripting and did not understand this. Thank you so much. If you transfer your comment to the answers section I'll accept it.
    – MykelXIII
    Commented Jul 2, 2015 at 13:35
  • I tried to expand on my answer as much as possible to make the picture as clear and simple to understand as I could.
    – HalosGhost
    Commented Jul 2, 2015 at 14:05

2 Answers 2


Okay, let's break this down. A subshell executes its contents in a chain (i.e., it groups them). This actually makes intuitive sense as a subshell is created simply by surrounding the chain of commands with (). But, aside from the contents of the subshell being grouped together in execution, you can still use a subshell as if it were a single command. That is, a subshell still has an stdin, stdout and stderr so you can pipe things to and from a subshell.

On the other hand, command substitution is not the same thing as simply chaining commands together. Rather, command substitution is meant to act a bit like a variable access but with a function call. Variables, unlike commands, do not have the standard file descriptors so you cannot pipe anything to or from a variable (generally speaking), and the same is true of command substitutions.

To try to make this more clear, what follows are a set of maybe-unclear (but accurate) examples and a set of, what I think may be, more easily-understood examples.

Let's say the date -u command gives the following:

Thu Jul  2 13:42:27 UTC 2015

But, we want to manipulate the output of this command. So, let's pipe it into something like sed:

user@host~> date -u | sed -e 's/ /    /g'
Thu    Jul        2    13:42:27    UTC    2015

Wow, that was fun! The following is completely equivalent to above (barring some environment differences that you can read about in the man pages about your shell):

user@host~> (date -u) | sed -e 's/ /    /g'
Thu    Jul        2    13:42:27    UTC    2015

That should be no surprise since all we did was group date -u. However, if we do the following, we are going to get something that may seem a bit odd at first:

user@host~> $(date -u) | sed -e 's/ /    /g'
command not found: Thu

This is because $(date -u) is equivalent to typing out exactly what date -u outputs. So the above is equivalent to the following:

user@host~> Thu Jul  2 13:42:27 UTC 2015 | sed -e 's/ /    /g'

Which will, of course, error out because Thu is not a command (at least not one I know of); and it certainly doesn't pipe anything to stdout (so sed will never get any input).

But, since we know that command substitutions act like variables, we can easily fix this problem because we know how to pipe the value of a variable into another command:

user@host~> echo $(date -u) | sed -e 's/ /    /g'
Thu    Jul        2    13:42:27    UTC    2015

But, as with any variable in bash, you should probably quote command substitutions with "".

Now, for the perhaps-simpler example; consider the following:

user@host~> pwd
user@host~> echo pwd
user@host~> echo "$(pwd)"
user@host~> echo "$HOME"
user@host~> echo (pwd)
error: your shell will tell you something weird that roughly means “Whoa! you tried to have me echo something that isn't text!”
user@host~> (pwd)

I am not sure how to describe it any simpler than that. The command substitution works just like a variable access where the subshell still operates like a command.



(command) will execute command in a subshell. This is useful, if you have more than one command.

  • (ls) | wc will pipe the output of ls to wc, obviously you can write ls | wc.
  • (ls ; date) | wc will pipe the output of both ls and date to wc. Using ls ; date | wc will result in only date being piped to wc.


$(command) will execute command and replace by the output. E.g.

echo $(date)

will replace $(date) by Thu Jul 2 15:20:43 CEST 2015, which results in

echo Thu Jul  2 15:20:43 CEST 2015

Putting both together

You can combine the two.

( printf "%s has %d bytes\n" "${file}" $(wc -c < "$file") ; date ) | netcat ...

Here, you can use "$file" or "${file}".

Do not forget to quote filename, in fantasy world filename are plain file, whereas in real world filename usually contains new line, space, comma, tabulation and parenthesis.

  • Does that mean that i cannot use command substitution on multiple commands such as using ; to separate them?
    – MykelXIII
    Commented Jul 2, 2015 at 13:29
  • Sure you can. It's just not going to pipe anything to stdout and will instead replace itself with the result of the expression.
    – HalosGhost
    Commented Jul 2, 2015 at 13:31
  • As Kusalananda says, “Displaying the output of a command using command substitution and echo is a bad example of command substitution because 1) the output would have been displayed anyway, 2) printf is safer to use for variable data.” I wonder how much the echo $(date) example helps anybody learn to understand command substitution. I am biased toward my own example, ls -ld $(date +%B).txt (which shows long information about the July.txt file). Commented Jul 30, 2020 at 21:53
  • P.S. As I’m sure you know, you should use "$file" (i.e., use quotes), not because your example needs it, but because we want to teach good habits and lead by example. Commented Jul 30, 2020 at 21:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .