2
$ head -c10G /dev/zero |
  tee >(head -c1M | wc -c) >(head -c10M | wc -c) >(head -c100M | wc -c) >(head -c1000M | wc -c)

gives:

1048576
1064960
1064960
1064960

I would have expected:

1048576
10485760
104857600
1048576000

I imagine it is due to head -c1M closing the pipe and tee then only writes one block more to the other processes, before it discovers that it cannot write to the first process and then exits.

Can I ask tee to skip the closed receiver, but keep on writing to the others?

4

You should use tee --output-error=exit-nopipe. That would ignore the SIGPIPE signal and the EPIPE write error, but will still die on any other errors.

tee --output-error=exit-nopipe, just like the warn variant from your answer, does exit when it cannot write to at least one of its outputs; but it does count the standard output as one of them.

Your examples are buggy because they just dump the output of head -c10G /dev/zero | tee ... to your terminal (which you cannot see because the null byte is "invisible"); and that's why the tee in your answer doesn't exit: because it will be still writing to stdout after the >(...) process substitutions have exited.

For systems without GNU tee, a possible workaround is to append a cat >/dev/null to the commands the output of tee is piped to; but you cannot do that with all of them; you'll have to decide on a "master" output which will cause tee to exit if writing to it doesn't succeed. Example:

$ dd if=/dev/zero |
  tee >(dd of=/dev/null count=200; cat >/dev/null) >(dd of=/dev/null count=700; cat >/dev/null) |
  dd of=/dev/null count=1000
$ dd if=/dev/zero |
  tee >(dd of=/dev/null count=1000) >(dd of=/dev/null count=700; cat >/dev/null) |
  { dd of=/dev/null count=200; cat >/dev/null; }

Both should write 200, 700 and 1000 blocks respectively.

  • Try tee -p, example: head -c5M /dev/zero | tee -p >(dd count=4000) >(dd count=700) – Isaac Oct 8 '18 at 11:30
  • 1
    @Isaac tee -p will continue happily running even after an EIO or ENOSPC error when writing to a regular file; you usually don't want that, so --output-error=exit-nopipe is better. – mosvy Oct 8 '18 at 16:33
  • Can anyone hazard a guess as to why exit-nopipe is not default.. ? (Note: pee from moreutils ignores SIGPIPE) – olejorgenb Jan 26 at 13:53
0

It seems --output-error=warn does this.

head -c10G /dev/zero |
  tee --output-error=warn >(head -c10M | wc -c) >(head -c100M | wc -c) >(head -c1000M | wc -c)

Unfortunately it also spams warnings on stderr and it does not exit if it cannot write to any of them.

  • 1
    tee --output-error=warn will exit if it cannot write to any of its outputs -- it just counts the stdout as one of them. Use warn-nopipe instead of warn if you want to suppress the spurious errors. Another possible workaround for systems without GNU tee is to add a cat >/dev/null after the commands in the process substitutions: eg >(head ...; cat >/dev/null). – mosvy Oct 6 '18 at 19:11
0

It happens that any pipe that blocks will send a SIGPIPE to tee and stop it:

$ head -c10G /dev/zero |   tee >(head -c10 | wc -c) >(head -c1M | wc -c)
10
65536

The command tee is receiving the SIGPIPE from the first pipe and causing all the childs to exit.

You would need to expand each pipe to have no limit:

$ head -c10G /dev/zero |   tee >({ head -c10 | wc -c; }; cat >/dev/null )  >(head -c1M | wc -c)
10
1048576

for all the cases you have given:

$ head -c10G /dev/zero |   tee >({ head -c1M | wc -c;}; cat >/dev/null) >({ head -c10M | wc -c; }; cat >/dev/null) >( { head -c100M | wc -c; }; cat>/dev/null) >(head -c1000M | wc -c)
1048576
10485760
104857600
1048576000

But it is simpler to tell tee to avoid exiting on pipe errors with the -p option:

$ head -c10M /dev/zero |   tee -p >(head -c10 | wc -c) >(head -c100 | wc -c) >(head -c1000| wc -c) >(head -c1M | wc -c)
100
1000
10
1048576

Which might print out of order.

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.