Bash is simply insane

What do you think the following script ((The script is somewhat artificial, who would ever use the construct true | while ...? I’ve used this just to show the point while keeping the examples short. Feel free to replace that part with something more useful, like cat myfile | while read ....)) will print?

Run it and see. I suspect everyone but the script gurus out there will be surprised.

What about this script then?

Surprised again?

I guess this means that scoping in bash is somewhat more complicated then I would have ever guessed.

⟸ Playing with sockets in Haskell Gnome: 2 questions that go unanswered ⟹

Max

it depends on shell - they can run the tail of pipe in subprocess or not

in zsh foo fails, in dash foo prints 1

Nikolay Orlyuk

That’s because of that ‘|’ I guess. It have to run it in separate process and “while” should be executed also in other process (or emulated somehow that) to connect stdin with stdout of “true”.

You can get “proper” (modified in the same sh-process as “while”) value of “rc” by:

true | {
  while true; do
  # ... (return will get out of { }, so probably break instead)
  done
  echo $?
  echo $rc
}

ephemient

It’s not just Bash, it’s all Bourne-like shells. I knew what was going to happen, but probably I’ve been doing too much shell programming ;)

The explanation is actually pretty simple. There’s two things at play here: pipes force subshells, and pipe’s return status is the tail’s return status.

i.e. “echo | while read; do :; done” == “echo | (while read; do :; done)” and “false | true” returns 0, “true | false” returns 1.

Magnus

Nikolay Orlyuk, Well, that doesn’t do much to help the problem. There are still no clear visual clues that a sub-shell is used, and lexical scoping doesn’t exist.

ephemient, Yes, it’s simple to explain, but there are no clear visual clues that a sub-shell is used. That’s what bothers me about it. Anyone coming from a programming lanugage with proper lexical scoping and sane semantics of return will be surprised.

Oh well, it’s just another argument to avoid writing anything but very short scripts in shell.

lilac

Don’t avoid writing scripts in shell. Just avoid writing scripts for bash :) zsh behaves exactly as I would expect in the above (and many other) cases.

anonymous

It’s less than ideal all right, but the bash manual does say “Each command in a pipeline is executed as a separate process (i.e., in a subshell).”

Leave a comment