[Marek Gibney] poses an interesting puzzle. What does the following bash command line print?
( echo red ; echo green 1>&2 ) | echo blue
You’d like to think it prints three lines: red, green, and blue. But would you be surprised to find out that it can sometimes output “blue green” and sometimes just output blue. The first surprise is that it isn’t deterministic. But the second thing that is surprising is the sometimes the entire left-hand part of the line doesn’t do anything. [Chris Siebenmann] did the analysis and explains what’s going on in a recent blog post.
Before you click the link or read further, you might want to see if you can deduce what’s going on. Give up? Here’s a hint: Part of the solution hinges on the fact that echo is built into the shell.
Breaking the command line down, the left part will spin off a subshell. The “echo blue” part runs in the original shell. Keep in mind that since echo is built-in, there won’t be more processes. The echo red gets piped to the right-hand part and it ignores the input. However, the green part redirects to the stderr stream, so it makes sense you’d get some combination of blue and green, but then why do you sometimes get just blue?
According to [Chris], there are three possible outcomes:
- The left side prints green and exits before the right side tries to write. You get green blue.
- The left side prints red, the right side prints blue, and then the second part of the left side prints green. You get blue green.
- Echo blue runs first and ends. The echo red then tries to write to a broken pipe and dies with a SIGPIPE signal.
This is a good example of how simple tools can combine in surprising ways and sometimes even the simplest commands can require an understanding of underlying details that might seem unimportant.
You could argue, of course, that the line isn’t a great example of shell script. That’s true, but you don’t always pick the code you are analyzing.