On 20/11/15 02:20, Pádraig Brady wrote:
> I'm coming around to making a change here.
> 
> Either be quiet about:
>   datagen | tee >(sha1sum --tag) >(md5sum --tag) >&- | sort | gpg --clearsign
> 
> Or support:
>   datagen | tee --no-stdout >(sha1sum --tag) >(md5sum --tag) | sort | gpg 
> --clearsign
> 
> I like the idea of supporting this with no new option.
> I see we have similar EBADF handling in touch and nohup.
> I'll sleep on it.

The attached supports the >&- usage above.

cheers,
Pádraig.

>From bbd741b0eb290ff94b8f0f4bbe40d4fc7e9e5ea3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <p...@draigbrady.com>
Date: Fri, 20 Nov 2015 11:54:00 +0000
Subject: [PATCH] tee: don't diagnose a closed standard output

This can be useful if you want data from process substitutions
coalesced through stdout. For example:
  datagen | tee >(md5sum --tag) >(sha256sum --tag) >&- | sort

* src/tee.c (tee_files): Don't diagnose EBADF on stdout.
* tests/misc/tee.sh: Add a test case.
* doc/coreutils.texi (tee invocation): Mention that -p is
useful with pipes that may not consume all data.
Add a closed stdout example, similar to the one above.
* NEWS: Mention the change in behavior.
* THANKS.in: Add the suggester, Jirka Hladky.
---
 NEWS               |  3 +++
 THANKS.in          |  1 +
 doc/coreutils.texi | 16 ++++++++++++++++
 src/tee.c          |  8 +++++++-
 tests/misc/tee.sh  |  7 +++++++
 5 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index fc5e927..5fe0ea2 100644
--- a/NEWS
+++ b/NEWS
@@ -35,6 +35,9 @@ GNU coreutils NEWS                                    -*- outline -*-
   ls now quotes file names unambiguously and appropriate for use in a shell,
   when outputting to a terminal.
 
+  tee no longer diagnoses write errors to a closed standard output, as this
+  can be useful when further piping the output from process substitutions.
+
 ** Improvements
 
   All utilities now quote user supplied arguments in error strings,
diff --git a/THANKS.in b/THANKS.in
index 51c77ef..5c49006 100644
--- a/THANKS.in
+++ b/THANKS.in
@@ -299,6 +299,7 @@ Jesse Thilo                         j...@eecs.lehigh.edu
 Jie Xu                              x...@iag.net
 Jim Blandy                          j...@cyclic.com
 Jim Dennis                          j...@starshine.org
+Jirka Hladky                        jhla...@redhat.com
 Joakim Rosqvist                     dvl...@cs.umu.se
 Jochen Hein                         joc...@jochen.org
 Joe Orton                           j...@manyfish.co.uk
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 8034807..1755a51 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -13019,6 +13019,11 @@ so it works with @command{zsh}, @command{bash}, and @command{ksh},
 but not with @command{/bin/sh}.  So if you write code like this
 in a shell script, be sure to start the script with @samp{#!/bin/bash}.
 
+Note also that if any of the process substitutions (or piped stdout)
+might exit early without consuming all the data, the @option{-p} option
+is needed to allow @command{tee} to continue to process the input
+to any remaining outputs.
+
 Since the above example writes to one file and one process,
 a more conventional and portable use of @command{tee} is even better:
 
@@ -13087,6 +13092,17 @@ tar chof - "$tardir" \
   | bzip2 -9 -c > your-pkg-M.N.tar.bz2
 @end example
 
+If you want to further process the output from process substitutions,
+and those outputs are smaller than the system's PIPE_BUF size, resulting
+in atomic writes, it's useful to close stdout like:
+
+@example
+tardir=your-pkg-M.N
+tar chof - "$tardir" \
+  | tee >(md5sum --tag) >(sha256sum --tag) >&- \
+  | sort | gpg --clearsign > your-pkg-M.N.tar.sig
+@end example
+
 @exitstatus
 
 
diff --git a/src/tee.c b/src/tee.c
index ae1bb30..9ef7742 100644
--- a/src/tee.c
+++ b/src/tee.c
@@ -246,7 +246,13 @@ tee_files (int nfiles, char **files)
             bool fail = errno != EPIPE || (output_error == output_error_exit
                                           || output_error == output_error_warn);
             if (descriptors[i] == stdout)
-              clearerr (stdout); /* Avoid redundant close_stdout diagnostic.  */
+              {
+                /* Don't diagnose a closed stdout.  */
+                if (errno == EBADF)
+                  fail = false;
+                /* Avoid redundant close_stdout diagnostic.  */
+                clearerr (stdout);
+              }
             if (fail)
               {
                 error (output_error == output_error_exit
diff --git a/tests/misc/tee.sh b/tests/misc/tee.sh
index f457a0b..bc51c9a 100755
--- a/tests/misc/tee.sh
+++ b/tests/misc/tee.sh
@@ -63,6 +63,13 @@ if test -w /dev/full && test -c /dev/full; then
   test $(wc -l < err) = 1 || { cat err; fail=1; }
 fi
 
+# Ensure tee doesn't diagnose a closed stdout
+# which can be useful when coalescing small atomic outputs
+# from process substitutions like:
+# $ seq 100000 | tee -p >(head -n10 | wc -l) >(wc -l) >&- | cat
+# 10
+# 100000
+echo | tee >&- || fail=1
 
 # Ensure tee honors --output-error modes
 mkfifo_or_skip_ fifo
-- 
2.5.0

Reply via email to