From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FROM,HTML_MESSAGE,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 27966 invoked from network); 12 Nov 2022 22:18:07 -0000 Received: from zero.zsh.org (2a02:898:31:0:48:4558:7a:7368) by inbox.vuxu.org with ESMTPUTF8; 12 Nov 2022 22:18:07 -0000 ARC-Seal: i=1; cv=none; a=rsa-sha256; d=zsh.org; s=rsa-20210803; t=1668291487; b=OHhHV9u88yv+aafXfj+0dC7EIGfpRfMRhPF7qnhlqg/Gr9p0YKM+eDpHTNIUoBlMjHkd+NpPnz bcX/G5ZmshlbADkuJ3id3armv4bx1fC9568NZ/yCqMACG8EFxxyRF4zsl6+ur48f8dedHB5qRA 9KEn9jdc7kTfQDaljBzw04hB3DvYS1woC4/GZGImdfT9DORxoxNcOOxxxuwswC3C05rcn52FXs Zxh80ZutS5CLyqK+KjoZ/6D4tFKd4y9OdAO6sFINNmruQJ3DjMtVDugdqMiNlNR4ZTepESDMA0 vRSoGVgCBeusGbwMHIB+mxpaZBPRUNPuQ9L9IjwkfGLgOQ==; ARC-Authentication-Results: i=1; zsh.org; iprev=pass (mail-ua1-f46.google.com) smtp.remote-ip=209.85.222.46; dkim=pass header.d=gmail.com header.s=20210112 header.a=rsa-sha256; dmarc=pass header.from=gmail.com; arc=none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed; d=zsh.org; s=rsa-20210803; t=1668291487; bh=Fca9Sl5rHScn7ZHwZ6uP1IBCXVthiWaYaRF32kQhG/o=; h=List-Archive:List-Owner:List-Post:List-Unsubscribe:List-Subscribe:List-Help: List-Id:Sender:Content-Type:To:Subject:Message-ID:Date:From:MIME-Version: DKIM-Signature:DKIM-Signature; b=a06oTXxZAr7ubMdCIQqGT+rdt0Pyk0T/XO/dAzoNK8Z63cDqjX/j6KTmlBPCQOubFYVXxsrG1v 8QtyIEPzVkPzKsICj1iauouWVULdji/meMGY1hC/IwX1R3SxYQ4w2xPFGF5ax9T2LnUCEKhZo3 ObVjA5qr5PH5aypqZ7ymWK2/F87RnzryPHsGYjW1AyXqSopr4h/jGHCFfeYjjstyApoRThpnZv xti69CTWBiEntYtXALt8sl/saDja8IZ5V8T68DoEG8bLRe/4HhU02S/UFgD4dmSR3y4YHzWTlp floew4WGvjr+pECk3H64miGGPgYxzK4TPXO1IWx2Nerp3w==; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=zsh.org; s=rsa-20210803; h=List-Archive:List-Owner:List-Post:List-Unsubscribe: List-Subscribe:List-Help:List-Id:Sender:Content-Type:To:Subject:Message-ID: Date:From:MIME-Version:Reply-To:Cc:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References; bh=rnVIirFW66Zn8xVzK3C6M3fnS/Us3r0h8az02rAprMg=; b=B5UGJK5Yy9MSwrJdOI1J5rsdaz ORjsB8QRcY9cLmwPhitAAk9dijfBNhpWNKVdCnGUBj2yb9WpCDS/bstAxbphsh4Jg/ExMX81AOEZL nh1T40xhRXbmjeCMsPxcQ+gXMDEt6P1qBAjuzPoR1tJBulGhau7FaBQancwyTDOFzmVGsHKRCnd5z hwtCELnKAN4BY5vtKp/VA/3KZB4H1KyC8c085xS/hsZoCW7o0uKUMBPCIB0GUQM8o7u0mCLO65MH6 Ef/IBRbLaTwD749oWWcQC6V3wSpsFIwJ7xVRpCJ+Jx8DZ4eruGtma5kOcD/msHhm0F0qSquxG7jhD WD65ua0Q==; Received: by zero.zsh.org with local id 1otypC-0004tN-Rg; Sat, 12 Nov 2022 22:18:06 +0000 Authentication-Results: zsh.org; iprev=pass (mail-ua1-f46.google.com) smtp.remote-ip=209.85.222.46; dkim=pass header.d=gmail.com header.s=20210112 header.a=rsa-sha256; dmarc=pass header.from=gmail.com; arc=none Received: from mail-ua1-f46.google.com ([209.85.222.46]:39860) by zero.zsh.org with esmtps (TLS1.3:TLS_AES_128_GCM_SHA256:128) id 1otynp-00044F-QR; Sat, 12 Nov 2022 22:16:42 +0000 Received: by mail-ua1-f46.google.com with SMTP id x20so2503833ual.6 for ; Sat, 12 Nov 2022 14:16:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=rnVIirFW66Zn8xVzK3C6M3fnS/Us3r0h8az02rAprMg=; b=NDIV5ZyOqtciaBqM62tQyOpM4NW4e0E3uanbto7f7yR+OxJPptJue9FE7bGKdAmdyL mbPrXsAfamEJfYcYk06OEcEzLqPfihwksJPUddCm4xfFZXivVrZ3em4Iup8HmguS8zLT SaSbdk51DDJ9qtFxMCNa8pSts03QyHL2eKRkvSjhZdJR3XINlWoqS4zY7FCg3CoQH8vN 2376BzYKasmbvzwb2FBkbJEI9h2hnAiHIxcfIhxf6BtMixtyiwzTixM6wB4rDsYzLiJ5 S2gq9TpkRPG1F8/cKZPmKKYYTnTmYfDE9uWQaHGwhQeYWsrMqqjkh247AA+R6ZgryYdb rPig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=rnVIirFW66Zn8xVzK3C6M3fnS/Us3r0h8az02rAprMg=; b=JK2NUH6Ldh+PdfjZNxvnxzAMb00p/A7FRGHlC9jmTNJZtBe4wk7VJbqw31ZzLi7shI FGO4oRq3MvUbmZ9rNW61YcSwZK73a9nEd/CNOOR1jyppRs+L0T/LCNsqUggCc4kuA+Cs iiFt95x5JOOF4ZFlkmdk9A0R6BjTEKVd4u1U8Ri+ztVsJ6gKU9M1Af+YLKaP9L8LSjeu AEoX4h0TvWMj8vo4bml5bnITUXXBgek5lmR30Muy34sy7LVoxQB8PMdXD7kYh93OxjYQ VSxNmOQODVkjBa7Zndw+0HTyIu/VJh3GYIWL095xgBYZLvzPdBIQ/dOWaFSnBlrpNmkP 4yAw== X-Gm-Message-State: ANoB5pmkqbb/2eGS1ck7WTQSPx+jAMQOI9RO0n2YY16ecwNYojjQ0bHd bEMysbyqs9/14v5fizljrV4PH3j3M/OEZcB2uYiLcvqPw9A= X-Google-Smtp-Source: AA0mqf5J+pxSx8cMzqhud+FiSZk+e8LQkolGcUA92a2cmxffJZQs7uFuyFYTXpKNJmVP9FXGSFQnLeS78WK8lI3l0Qo= X-Received: by 2002:ab0:1e08:0:b0:411:336c:b7be with SMTP id m8-20020ab01e08000000b00411336cb7bemr3522278uak.6.1668291400439; Sat, 12 Nov 2022 14:16:40 -0800 (PST) MIME-Version: 1.0 From: Philippe Altherr Date: Sat, 12 Nov 2022 23:16:29 +0100 Message-ID: Subject: Re: [PATCH] More ERR_EXIT (was Re: Tests RE behavior of ERR_EXIT) To: Bart Schaefer , zsh-workers@zsh.org Content-Type: multipart/alternative; boundary="0000000000004e1d1105ed4d5ce7" X-Seq: 50944 Archived-At: X-Loop: zsh-workers@zsh.org Errors-To: zsh-workers-owner@zsh.org Precedence: list Precedence: bulk Sender: zsh-workers-request@zsh.org X-no-archive: yes List-Id: List-Help: , List-Subscribe: , List-Unsubscribe: , List-Post: List-Owner: List-Archive: --0000000000004e1d1105ed4d5ce7 Content-Type: text/plain; charset="UTF-8" Hi Bart, I just noticed the following change: +Changes since 5.9 > +----------------- > + > +Handling of ERR_EXIT is corrected > *when the final status of a structured+command* (for, select, while, > repeat, if, case, or a list in braces) > *is+nonzero*. To be compatible with other shells, *"zsh -e" now exits* in > +those circumstances, whereas previous versions did not. This does not > +affect the handling of nonzero status within conditional statements. This looks wrong to me. It's not compatible with the third exception of POSiX "set -e" : When this option is on, when any command fails (for any of the reasons > listed in Consequences of Shell Errors or by returning an exit status > greater than zero), the shell immediately shall exit, as if by executing > the exit special built-in utility with no arguments, with the following > exceptions: > > 1. The failure of any individual command in a multi-command pipeline > shall not cause the shell to exit. Only the failure of the pipeline itself > shall be considered. > 2. The -e setting shall be ignored when executing the compound list > following the while, until, if, or elif reserved word, a pipeline beginning > with the ! reserved word, or any command of an AND-OR list other than the > last. > 3. *If the exit status of a compound command other than a subshell > command was the result of a failure while -e was being ignored, then -e > shall not apply to this command.* > > My high-level understanding of exception 3 is that if an error was produced by a condition (note that the last command in a sub-list is NOT a condition but a regular command), then that error should bubble up the evaluation stack, without triggering any ERR_EXIT, until it gets ignored (for example on the left of a ";" in a sequence) or it becomes the result of an enclosing function or subshell. Let's consider the following example: function foo() { if true; then false && true; fi } > function bar() { foo } > bar Exception 2 tells us that "false && true" shouldn't trigger an ERR_EXIT. By exception 3, the resulting exit status becomes the result, first of the enclosing if, and then of the enclosing {}, without triggering an ERR_EXIT. It's only in function "bar" that an "ERR_EXIT" should be triggered because the call to "foo" returns 1 and function calls aren't compound commands. Zsh 5.8.1, doesn't trigger any ERR_EXIT for this example. Zsh 5.9.*, with your latest changes, triggers an ERR_EXIT in "foo". Bash 5.1.16 triggers an ERR_EXIT in "bar". My understanding is that Bash is right. Here is the script that I used to test this behavior with Zsh and Bash (for bash you have to comment out the "foo?3" tests): # test.zsh > # Usage: test.zsh A1|...|A4|B1|...|B4|C1|...|C4 > # > # Example: "test.zsh A1" runs the test for "fooA1". > set -e > function err-exit() { > local error=$?; > # Print where ERR_EXIT was called from. > if [[ -n $ZSH_VERSION ]]; then > local file=${funcfiletrace[1]%:*} > local line=${funcfiletrace[1]#*:} > elif [[ -n $BASH_VERSION ]]; then > local caller=$(caller 0); > local file=${caller##* } > local line=${caller%% *} > fi > echo "Caught error $error at $file:$line: $(cat $file | head -$line | > tail -1)" >&2 > return $error; > } > trap err-exit ERR > if [[ -n $ZSH_VERSION ]]; then > alias init='' > elif [[ -n $BASH_VERSION ]]; then > # It looks like in Bash the ERR trap must be set in every function > shopt -s expand_aliases > alias init='trap err-exit ERR' > fi > function fooA1() { init; false ; > } > function fooA2() { init; if true; then false ; fi > } > function fooA3() { init; { false ; } always { true; } > } > function fooA4() { init; { false ; } > } > function fooB1() { init; false && true; > } > function fooB2() { init; if true; then false && true; fi > } > function fooB3() { init; { false && true; } always { true; } > } > function fooB4() { init; { false && true; } > } > function fooC1() { init; false && true ; > echo foo; } > function fooC2() { init; if true; then false && true; fi ; > echo foo; } > function fooC3() { init; { false && true; } always { true; }; > echo foo; } > function fooC4() { init; { false && true; } ; > echo foo; } > function bar() { > init > echo Start > foo$1 > echo End > } > bar "$@" I included the "foo?3" tests because all the compound commands in loop.c seem to behave the same except for "exectry", which lacks the following line: this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END); I included the "foo?4" tests because sequences are not handled by one of the functions in loop.c but by some function in exec.c. However, all "foo?3" and "foo?4" tests nevertheless behave the same as the matching "foo?2" tests. Here are the results: Zsh 5.8.1 Zsh 5.9.* Bash 5.1.16 fooA1 Exit in foo* Exit in foo* Exit in foo* > fooA2 Exit in foo* Exit in foo* Exit in foo* fooB1 Exit in bar Exit in bar Exit in bar > fooB2 No exit Exit in foo* Exit in bar fooC1 No exit No exit No exit > fooC2 No exit Exit in foo* No exit My understanding is that Bash's behavior is the correct one. Philippe --0000000000004e1d1105ed4d5ce7 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi Bart,

I just noticed the following c= hange:

POSiX &= quot;set -e":

When this option is on, when any command fails (for = any of the reasons listed in Consequences of Shell Errors or by returning a= n exit status greater than zero), the shell immediately shall exit, as if b= y executing the exit special built-in utility with no arguments, with the f= ollowing exceptions:
  1. The failure of any individual command in a = multi-command pipeline shall not cause the shell to exit. Only the failure = of the pipeline itself shall be considered.
  2. The -e setting shall be= ignored when executing the compound list following the while, until, if, o= r elif reserved word, a pipeline beginning with the ! reserved word, or any= command of an AND-OR list other than the last.
  3. If the exit stat= us of a compound command other than a subshell command was the result of a = failure while -e was being ignored, then -e shall not apply to this command= .
My high-level understanding of exception 3 is t= hat if an error was produced by a condition (note that the last command in = a sub-list is NOT a condition but a regular command), then that error shoul= d bubble up the evaluation stack, without triggering any ERR_EXIT, until it= gets ignored (for example on the left of a ";" in a sequence) or= it becomes the result of an enclosing function or subshell.

=
Let's consider the following example:

function foo() { if true; t= hen false && true; fi }
function bar() { foo }
bar

Exception 2 tells us that "false && true= " shouldn't trigger an ERR_EXIT. By exception 3, the resulting exi= t status becomes the result, first of the enclosing if, and then of the enc= losing {}, without triggering an ERR_EXIT. It's only in function "= bar" that an "ERR_EXIT" should be triggered because the call= to "foo" returns 1 and function calls aren't compound comman= ds.

Zsh 5.8.1, doesn't trigger any ERR_EXIT fo= r this example. Zsh 5.9.*, with your latest changes, triggers an ERR_EXIT i= n "foo". Bash 5.1.16 triggers an ERR_EXIT in "bar". My = understanding is that Bash is right.

Here is the s= cript that I used to test this behavior with Zsh and Bash (for bash you hav= e to comment out the "foo?3" tests):

# t= est.zsh
# Usage: test.zsh A1|...|A4|B1|...|B4|C1|...|C4
#
# Exampl= e: "test.zsh A1" runs the test for "fooA1".

set -e
<= blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-l= eft:1px solid rgb(204,204,204);padding-left:1ex"><= br>
function err-exit() {
=C2=A0 =C2=A0 local error=3D$?;
=C2= =A0 =C2=A0 # Print where ERR_EXIT was called from.
=C2=A0 =C2=A0 if [[ -n $ZSH_VERSION ]]; then
=C2=A0 =C2=A0 =C2=A0 =C2=A0 local file=3D${funcfiletrace[1]= %:*}
=C2=A0 =C2=A0 =C2=A0 =C2=A0 local l= ine=3D${funcfiletrace[1]#*:}
=C2=A0 =C2= =A0 elif [[ -n $BASH_VERSION ]]; then
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 local caller=3D$(caller 0);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 local file=3D${caller##* }
<= /font>=C2=A0 =C2=A0 =C2=A0 =C2=A0 local line=3D${c= aller%% *}
=C2=A0 =C2=A0 fi
=C2=A0 =C2=A0 echo "Caught error $error at $fil= e:$line: $(cat $file | head -$line | tail -1)" >&2
=C2=A0 =C2=A0 return $error;
}

trap err-exit ERR=
if [[ -n $ZSH_VERSION ]]; then
=C2=A0 =C2=A0 alias init=3D''
= elif [[ -n $BASH_VERSION ]]; then
=C2=A0 =C2=A0 # It looks like in Bash the ERR trap must = be set in every function
=C2=A0 =C2=A0 s= hopt -s expand_aliases
=C2=A0 =C2=A0 ali= as init=3D'trap err-exit ERR'
fi=

function fooA1() { init; =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 false =C2=A0 =C2=A0 =C2=A0 =C2= =A0; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }
fun= ction fooA2() { init; if true; then false =C2=A0 =C2=A0 =C2=A0 =C2=A0; fi = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0}
function fooA3= () { init; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 { false =C2=A0 =C2=A0 = =C2=A0 =C2=A0; } always { true; } =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= }
function fooA4() { init; =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 { false =C2=A0 =C2=A0 =C2=A0 =C2=A0; } =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 }

= function fooB1() { init; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f= alse && true; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }
function fooB2() { init; if true; then false && true= ; fi =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0}
function fo= oB3() { init; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 { false && = true; } always { true; } =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
function fooB4() { init; =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 { false && true; } =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }

function fooC1() { init; =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 false && true =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0; echo foo; }function fooC2() { init; if true; then fal= se && true; fi =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0; echo foo; }
function fooC3() { init= ; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 { false && true; } alwa= ys { true; }; echo foo; }
function fooC4= () { init; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 { false && tru= e; } =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ; echo foo; }<= /font>

function bar() {
=C2=A0 =C2=A0 init
= =C2=A0 =C2=A0 echo Start
=C2=A0 =C2=A0 f= oo$1
=C2=A0 =C2=A0 echo End
}

bar &qu= ot;$@"

I included t= he "foo?3" tests because all the compound commands in loop.c seem= to behave the same except for "exectry", which lacks the followi= ng line:

=C2=A0 this_noerrexit =3D (WC_SUBLIST_TYPE(*end) !=3D WC_SUBLIST_END);<= /blockquote>

=C2=A0I included the "foo?4" test= s because sequences are not handled by one of the functions in loop.c but b= y some function in exec.c. However, all "foo?3" and "foo?4&q= uot; tests nevertheless=C2=A0behave the same as the matching "foo?2&qu= ot; tests.

Here are the results:

=C2=A0 =C2=A0 =C2=A0 =C2=A0 Zsh 5.8.1 =C2=A0 =C2=A0 =C2=A0Zsh 5.9.* =C2= =A0 =C2=A0 =C2=A0Bash 5.1.16=C2=A0
=C2=A0
fooA1 =C2=A0 Exit in foo* =C2=A0 Exit in foo* =C2=A0 Exit in foo*
f= ooA2 =C2=A0 Exit in foo* =C2=A0 Exit in foo* =C2=A0 Exit in foo*=C2=A0
=C2=A0
fooB1 =C2=A0 Exit in bar =C2=A0 = =C2=A0Exit in bar =C2=A0 =C2=A0Exit in bar
fooB2 =C2=A0 No exit =C2=A0 = =C2=A0 =C2=A0 =C2=A0Exit in foo* =C2=A0 Exit in bar=C2=A0
=C2=A0
fooC1 =C2=A0 No exit =C2=A0 =C2=A0 =C2=A0 =C2= =A0No exit =C2=A0 =C2=A0 =C2=A0 =C2=A0No exit
fooC2 =C2=A0 No exit =C2= =A0 =C2=A0 =C2=A0 =C2=A0Exit in foo* =C2=A0 No exit

My understanding is that Bash's behavior is the correct= one.

Philippe

--0000000000004e1d1105ed4d5ce7--