Most Popular Posts

Apr 13, 2015

Nuances of Command Piping in the Windows Command Shell

 

A key concept in command piping is the success/failure of the execution which is determined by the status code the command returns. 0 (zero) means “success” while any other value means “failure”.

Throughout this article, I’ll be using this successful command:

> cmd /c “exit 0

as well as this failing command:

> cmd /c “exit 42

Note: If you want to copy and paste some of these examples, make sure you fix the quotes, dashes, and other characters to their standard ASCII representations.

Execute on Failure ( || )

Executes the command on the right side if and only if the command on the left side has failed. This piped statement:

> cmd /c “echo left & exit 0 || echo right

prints “left” while this piped statement:

> cmd /c “echo left & exit 42 || echo right

prints “left” then “right”.

You can remember this syntax and behavior as the logical OR operation from the C language or its derivates – C++, Java, C#, etc.

Execute on Success ( && )

Executes the command on the right side if and only if the command on the left side has succeeded. This piped statement:

> cmd /c “echo left & exit 0 && echo right

prints “left” then “right” while this piped statement:

> cmd /c “echo left & exit 42 && echo right

prints only “left”.

Similarly to the previous one, you can remember this syntax and behavior as the logical AND operation from the C language family.

Execute in Parallel ( | )

You may be familiar with this one – this is the true pipe. The shell connects the stdout of the left command to the stdin of the right command.

What you may have not paid attention to is that the shell launches both of them in parallel. That is necessary for the pipe to have a live process on each end.

To demonstrate the parallelism, we’ll need to enhance/complicate our left command a little bit:

cmd /c "echo left begin >&2 & timeout /t 5 & echo left end >&2 & exit 0"

First it prints “left begin” (to stderr to avoid the piping, so we can see the output), then it sleeps for 5 seconds to simulate work, and then it prints “left end” right before exiting.

Success and failure don’t matter. Both of these piped statements:

> cmd /c "echo left begin >&2 & timeout /t 5 & echo left end >&2 & exit 0" | echo right

and

> cmd /c "echo left begin >&2 & timeout /t 5 & echo left end >&2 & exit 42" | echo right

print “left begin” and “right”, then sleep for 5 seconds, and then it prints “left end”.

Execute Sequentially ( & )

This is the simplest yet least popular of all variations – it executed the right command after the left command has finished regardless of success/failure.

Using the same commands from the previous section:

> cmd /c "echo left begin >&2 & timeout /t 5 & echo left end >&2 & exit 0" & echo right

and

> cmd /c "echo left begin >&2 & timeout /t 5 & echo left end >&2 & exit 42" & echo right

both of them print “left begin”, sleep for 5 seconds, then print “left end” and “right”.

Relationship to POSIX

The first 3 syntaxes are identical between Windows cmd and bash. What is ‘&’ in Windows is ‘;’ (semicolon) in bash. Otherwise the behavior is the same.

No comments: