1

Given a function bar that runs echo bar every second forever, I expect bar | cat to print one line every second. It does not. It doesn't print anything until I hit ^C. There seems to be some superfluous buffering going on.

yes | cat works just fine. bar | cat works as expected in bash.

As to why this matters, please see this other question.

Community
  • 1
  • 1
mkaito
  • 1,005
  • 1
  • 10
  • 19
  • 1
    `echo` in `fish` apparently buffers its output. – Barmar Dec 14 '14 at 22:56
  • Would you say that this is a bug? – mkaito Dec 14 '14 at 22:57
  • Depends on whether it's documented and if there's a way to unbuffer it. – Barmar Dec 14 '14 at 22:57
  • I'm going to report it and see what the devs have to say about it. Could you post below so I can accept an answer? – mkaito Dec 14 '14 at 22:59
  • 1
    It's a known bug: https://github.com/fish-shell/fish-shell/issues/1396. Unlike all reasonable shells, `fish` runs pipelines sequentially, not in parallel. This seems like a fatal design error, you can't do something like `tail -f file | grep foo` – Barmar Dec 14 '14 at 23:08

1 Answers1

1

We have a command with a builtin in a pipeline:

echo bar | cat

bash forks new processes to execute builtins in pipelines. So there's two new processes: one for cat, the other to run the builtin echo. The processes are created with pipes connecting them, and they run independently.

fish always runs builtins directly, without creating new processes for them. So it executes echo bar, then sends the output to cat. The input and output for builtins and functions (but not external commands) is fully buffered. We're working on removing that limitation, but we're not there yet.

The bash behavior may seem more desirable in this case, but there's a heavy price for it, which is that builtins and functions do different things (or just don't work) inside pipelines. Example:

echo foo | read some_var ; echo $some_var

In fish, this will set some_var=foo, as you would expect. In bash, this silently fails: the assignment "works," but only within the transient process spawned to execute the read builtin, so the value isn't visible to the next command. This should give you some appreciation for why fish always runs builtins directly.

ridiculous_fish
  • 17,273
  • 1
  • 54
  • 61
  • I worked around it by turning `bar` into a bash script. You're right when you say that it has a heavy price. I just had wrong expectations. – mkaito Dec 15 '14 at 00:26