Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: No pipefail option?



On Fri, 4 Oct 2013 08:59:49 -0700
Shawn Halpenny <paxunix@xxxxxxxxx> wrote:
> It seems like it would be a good bash-compatibility option to have
> available.  I know we can check $pipestatus, but often I simply want to
> abort the script if any command in the pipeline failed without having to do
> an explicit check (similarly to how the errexit option works).  Explicit
> checks too easily get forgotten or overlooked or even just implemented
> incorrectly.

It's not impossible it's this simple.

Indeed, if $pipestatus is working as advertised, it really ought to be
this simple...

diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index ec86232..71bddd5 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -1683,6 +1683,20 @@ Sequences of digits indicating a numeric base such as the `tt(08)'
 component in `tt(08#77)' are always interpreted as decimal, regardless
 of leading zeroes.
 )
+pindex(PIPE_FAIL)
+pindex(NO_PIPE_FAIL)
+pindex(PIPEFAIL)
+pindex(NOPIPEFAIL)
+cindex(exit status from pipeline)
+cindex(status, on exit from pipeline)
+cindex(pipeline, exit status from)
+itme(tt(PIPE_FAIL))(
+By default, when a pipeline exits the exit status recorded by the shell
+and returned by the shell variable tt($?) reflects that of the
+rightmost element of a pipeline.  If this option is set, the exit status
+instead reflects the status of the rightmost element of the pipeline
+that was non-zero, or zero if all elements exited with zero status.
+)
 pindex(SOURCE_TRACE)
 pindex(NO_SOURCE_TRACE)
 pindex(SOURCETRACE)
diff --git a/Src/jobs.c b/Src/jobs.c
index e1b24b2..b9d7a84 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -508,15 +508,22 @@ update_job(Job jn)
     jn->stat |= (somestopped) ? STAT_CHANGED | STAT_STOPPED :
 	STAT_CHANGED | STAT_DONE;
     if (job == thisjob && (jn->stat & STAT_DONE)) {
-	int i;
+	int i, newlastval = 0;
 	Process p;
 
-	for (p = jn->procs, i = 0; p && i < MAX_PIPESTATS; p = p->next, i++)
+	for (p = jn->procs, i = 0; p && i < MAX_PIPESTATS; p = p->next, i++) {
 	    pipestats[i] = ((WIFSIGNALED(p->status)) ?
 			    0200 | WTERMSIG(p->status) :
 			    WEXITSTATUS(p->status));
-	if ((jn->stat & STAT_CURSH) && i < MAX_PIPESTATS)
+	    if (pipestats[i])
+		newlastval = pipestats[i];
+	}
+	if ((jn->stat & STAT_CURSH) && i < MAX_PIPESTATS) {
 	    pipestats[i++] = lastval;
+	    if (!lastval && isset(PIPEFAIL))
+		lastval = newlastval;
+	} else if (isset(PIPEFAIL))
+	    lastval= newlastval;
 	numpipestats = i;
     }
     if (!inforeground &&
diff --git a/Src/options.c b/Src/options.c
index ad869b2..ce73d99 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -205,6 +205,7 @@ static struct optname optns[] = {
 {{NULL, "overstrike",	      0},			 OVERSTRIKE},
 {{NULL, "pathdirs",	      OPT_EMULATE},		 PATHDIRS},
 {{NULL, "pathscript",	      OPT_EMULATE|OPT_BOURNE},	 PATHSCRIPT},
+{{NULL, "pipefail",           OPT_EMULATE},              PIPEFAIL},
 {{NULL, "posixaliases",       OPT_EMULATE|OPT_BOURNE},	 POSIXALIASES},
 {{NULL, "posixbuiltins",      OPT_EMULATE|OPT_BOURNE},	 POSIXBUILTINS},
 {{NULL, "posixcd",            OPT_EMULATE|OPT_BOURNE},	 POSIXCD},
diff --git a/Src/zsh.h b/Src/zsh.h
index e6f0f65..a46898d 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2121,6 +2121,7 @@ enum {
     OVERSTRIKE,
     PATHDIRS,
     PATHSCRIPT,
+    PIPEFAIL,
     POSIXALIASES,
     POSIXBUILTINS,
     POSIXCD,
diff --git a/Test/E01options.ztst b/Test/E01options.ztst
index bcb34c3..e00eb0e 100644
--- a/Test/E01options.ztst
+++ b/Test/E01options.ztst
@@ -1096,3 +1096,18 @@
 0:IGNORE_CLOSE_BRACES option
 >this is OK
 >6
+
+  (setopt pipefail
+  true | true | true
+  print $?
+  true | false | true
+  print $?
+  exit 2 | false | true
+  print $?
+  false | exit 2 | true
+  print $?)
+0:PIPE_FAIL option
+>0
+>1
+>1
+>2

-- 
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/



Messages sorted by: Reverse Date, Date, Thread, Author