7

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?

EDIT

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
  • 1
    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 Jul 2 '15 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 Jul 2 '15 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 Jul 2 '15 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 Jul 2 '15 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 Jul 2 '15 at 14:05
13

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:

$ 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):

$ (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:

$ $(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:

$ 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:

$ 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:

$ pwd
/home/hypothetical
$ echo pwd
pwd
$ echo "$(pwd)"
/home/hypothetical
$ echo "$HOME"
/home/hypothetical
$ 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!”
$ (pwd)
/home/hypothetical

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.

3

subshell

  • (command) will execute command in subshell, this is usefull, if you have more then one command.

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

substitution

  • $(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, then

    echo Thu Jul  2 15:20:43 CEST 2015

putting together

you can combine the two.

file=/hello/word
( printf "%s has %d bytes\n" ${file} $(wc -c < $file) ; date ) | netcat ... 
  • you can use $file or ${file}
  • Does that mean that i cannot use command substitution on multiple commands such as using ; to separate them? – MykelXIII Jul 2 '15 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 Jul 2 '15 at 13:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.