Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.unix.shell > #4871 > unrolled thread

[zsh] How to mimic errexit within subshell (or function)?

Started bykj <no.email@please.post>
First post2012-05-01 21:20 +0000
Last post2012-05-03 18:20 +0000
Articles 11 — 4 participants

Back to article view | Back to comp.unix.shell


Contents

  [zsh] How to mimic errexit within subshell (or function)? kj <no.email@please.post> - 2012-05-01 21:20 +0000
    Re: [zsh] How to mimic errexit within subshell (or function)? Stephane Chazelas <stephane.chazelas@gmail.com> - 2012-05-02 07:34 +0100
      Re: [zsh] How to mimic errexit within subshell (or function)? Geoff Clare <geoff@clare.See-My-Signature.invalid> - 2012-05-02 13:51 +0100
        Re: [zsh] How to mimic errexit within subshell (or function)? Stephane Chazelas <stephane.chazelas@gmail.com> - 2012-05-02 14:29 +0100
      Re: [zsh] How to mimic errexit within subshell (or function)? kj <no.email@please.post> - 2012-05-02 19:33 +0000
        Re: [zsh] How to mimic errexit within subshell (or function)? Stephane Chazelas <stephane.chazelas@gmail.com> - 2012-05-02 20:53 +0100
    Re: [zsh] How to mimic errexit within subshell (or function)? Martin Vaeth <vaeth@mathematik.uni-wuerzburg.de> - 2012-05-02 10:30 +0000
      Re: [zsh] How to mimic errexit within subshell (or function)? kj <no.email@please.post> - 2012-05-02 19:09 +0000
        Re: [zsh] How to mimic errexit within subshell (or function)? kj <no.email@please.post> - 2012-05-02 19:12 +0000
        Re: [zsh] How to mimic errexit within subshell (or function)? Stephane Chazelas <stephane.chazelas@gmail.com> - 2012-05-02 20:27 +0100
          Re: [zsh] How to mimic errexit within subshell (or function)? kj <no.email@please.post> - 2012-05-03 18:20 +0000

#4871 — [zsh] How to mimic errexit within subshell (or function)?

Fromkj <no.email@please.post>
Date2012-05-01 21:20 +0000
Subject[zsh] How to mimic errexit within subshell (or function)?
Message-ID<jnpk36$jqs$1@reader1.panix.com>

The following scheme doesn't work as expected: despite the set -e
(errexit), the subshell does not exit on error (it just goes on to
execute the next command):

#!/usr/bin/zsh
(
  set -e
  cmd0...
  cmd1...
  cmd2...
  ...
  echo "$0: done" 
) || { echo "$0: failed" && exit 1 }

How can I mimic the behavior of "set -e" within a subshell?  (Or
within a function, for that matter?)  (I realize that I can always
append "|| exit 1" to every command, but this is precisely what
I'd like to avoid.)

Thanks!

~kj

[toc] | [next] | [standalone]


#4872

FromStephane Chazelas <stephane.chazelas@gmail.com>
Date2012-05-02 07:34 +0100
Message-ID<20120502063438.GA10446@chaz.gmail.com>
In reply to#4871
2012-05-01 21:20:38 +0000, kj:
> 
> 
> The following scheme doesn't work as expected: despite the set -e
> (errexit), the subshell does not exit on error (it just goes on to
> execute the next command):
> 
> #!/usr/bin/zsh
> (
>   set -e
>   cmd0...
>   cmd1...
>   cmd2...
>   ...
>   echo "$0: done" 
> ) || { echo "$0: failed" && exit 1 }
> 
> How can I mimic the behavior of "set -e" within a subshell?  (Or
> within a function, for that matter?)  (I realize that I can always
> append "|| exit 1" to every command, but this is precisely what
> I'd like to avoid.)
[...]

Try 

zsh -ec '
  cmd1
  cmd2...
' || ...

Or:

(
  setopt nodebugbeforecmd
  TRAPDEBUG() { ((!$?)) || exit; }
  cmd1
  cmd2...
) || ...

I personally wouldn't touch "set -e" with a barge pole, and
would use some « || die '...' »

With die() being a function that takes an optional argument to
display on stderr and exits with a non-zero exit status.

-- 
Stephane

[toc] | [prev] | [next] | [standalone]


#4874

FromGeoff Clare <geoff@clare.See-My-Signature.invalid>
Date2012-05-02 13:51 +0100
Message-ID<f8n779-hk5.ln1@leafnode-msgid.gclare.org.uk>
In reply to#4872
Stephane Chazelas wrote:

> 2012-05-01 21:20:38 +0000, kj:
>> 
>> The following scheme doesn't work as expected: despite the set -e
>> (errexit), the subshell does not exit on error (it just goes on to
>> execute the next command):
>> 
>> #!/usr/bin/zsh
>> (
>>   set -e
>>   cmd0...
>>   cmd1...
>>   cmd2...
>>   ...
>>   echo "$0: done" 
>> ) || { echo "$0: failed" && exit 1 }

> Try 
>
> zsh -ec '
>   cmd1
>   cmd2...
> ' || ...

Or try

(
  set -e
  cmd1
  cmd2...
)
test $? -eq 0 || ...

(I don't have zsh, but that works in ksh, bash and dash).

-- 
Geoff Clare <netnews@gclare.org.uk>

[toc] | [prev] | [next] | [standalone]


#4875

FromStephane Chazelas <stephane.chazelas@gmail.com>
Date2012-05-02 14:29 +0100
Message-ID<20120502132926.GF10446@chaz.gmail.com>
In reply to#4874
2012-05-02 13:51:59 +0100, Geoff Clare:
> Stephane Chazelas wrote:
> 
> > 2012-05-01 21:20:38 +0000, kj:
> >> 
> >> The following scheme doesn't work as expected: despite the set -e
> >> (errexit), the subshell does not exit on error (it just goes on to
> >> execute the next command):
> >> 
> >> #!/usr/bin/zsh
> >> (
> >>   set -e
> >>   cmd0...
> >>   cmd1...
> >>   cmd2...
> >>   ...
> >>   echo "$0: done" 
> >> ) || { echo "$0: failed" && exit 1 }
> 
> > Try 
> >
> > zsh -ec '
> >   cmd1
> >   cmd2...
> > ' || ...
> 
> Or try
> 
> (
>   set -e
>   cmd1
>   cmd2...
> )
> test $? -eq 0 || ...
> 
> (I don't have zsh, but that works in ksh, bash and dash).
[...]

Indeed, though I had assumed "set -e" was also in effect in the
rest of the script (and "|| ..." was so that the failure of the
subshell wouldn't exit the script)

In that case, you can temporarily disable "set -e"

...
set +e
(
  set -e
  cmd1
  cmd2...
)
rc=$?
set -e
[ "$rc" -eq 0 ] || ...

-- 
Stephane

[toc] | [prev] | [next] | [standalone]


#4883

Fromkj <no.email@please.post>
Date2012-05-02 19:33 +0000
Message-ID<jns26e$h77$1@reader1.panix.com>
In reply to#4872
In <20120502063438.GA10446@chaz.gmail.com> Stephane Chazelas <stephane.chazelas@gmail.com> writes:

>Try 

>zsh -ec '
>  cmd1
>  cmd2...
>' || ...

>Or:

>(
>  setopt nodebugbeforecmd
>  TRAPDEBUG() { ((!$?)) || exit; }
>  cmd1
>  cmd2...
>) || ...


Thanks!

>I personally wouldn't touch "set -e" with a barge pole,


*gulp*, that's really bad news, since I have 'set -e' all over my
scripts...

I just searched for "set -e" bugs for zsh online, and found only
a couple of (sufficiently distinct-looking) hits:

  http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=520101
  http://permalink.gmane.org/gmane.linux.debian.devel.bugs.general/545456

Is this what you have in mind?

~k

[toc] | [prev] | [next] | [standalone]


#4884

FromStephane Chazelas <stephane.chazelas@gmail.com>
Date2012-05-02 20:53 +0100
Message-ID<20120502195328.GH10446@chaz.gmail.com>
In reply to#4883
2012-05-02 19:33:34 +0000, kj:
[...]
> >I personally wouldn't touch "set -e" with a barge pole,
> 
> 
> *gulp*, that's really bad news, since I have 'set -e' all over my
> scripts...
> 
> I just searched for "set -e" bugs for zsh online, and found only
> a couple of (sufficiently distinct-looking) hits:
> 
>   http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=520101
>   http://permalink.gmane.org/gmane.linux.debian.devel.bugs.general/545456
> 
> Is this what you have in mind?
[...]

No, that's about coding practice, maintainability and
reliability.

Relying on "set -e" to do your error handling is a bad idea in
anything more than the simplest of scripts that just run a
command after the other.

- commands can have non-zero exit statuses that don't mean an
  error (see "test", "expr", "grep"...)
- subtleties like the one you discovered about where its effects
  are cancelled
- interactions with subshells, pipes, background jobs
- some commands will output errors, some will no, "set -e" will
  not explain why the script dies.

You just can't assume it works without having to worry.

And if you start to worry, it's a lot simpler to do the error
handling properly.

That's my opinion anyway.

-- 
Stephane
- 

[toc] | [prev] | [next] | [standalone]


#4873

FromMartin Vaeth <vaeth@mathematik.uni-wuerzburg.de>
Date2012-05-02 10:30 +0000
Message-ID<slrnjq235r.qt6.vaeth@lounge.imp.fu-berlin.de>
In reply to#4871
kj <no.email@please.post> wrote:
>
> despite the set -e (errexit), the subshell does
> not exit on error

Here it does (in script and also interactive):

# ( set -e; printf a; false; printf b ); echo $?
a1

[toc] | [prev] | [next] | [standalone]


#4880

Fromkj <no.email@please.post>
Date2012-05-02 19:09 +0000
Message-ID<jns0pa$apr$1@reader1.panix.com>
In reply to#4873
First of all, thanks for all the replies!

In <slrnjq235r.qt6.vaeth@lounge.imp.fu-berlin.de> Martin Vaeth
<vaeth@mathematik.uni-wuerzburg.de> writes:

>kj <no.email@please.post> wrote:
>>
>> despite the set -e (errexit), the subshell does
>> not exit on error

>Here it does (in script and also interactive):

># ( set -e; printf a; false; printf b ); echo $?
>a1

Thanks.  But now I'm **really** confused.  I don't why the first
subshell below (i.e. your version) terminates upon error but the
second one (mine) doesn't:

% ( set -e; printf a; false; printf b ); echo $?
a1
% ( set -e; printf a; false; printf b ) || echo $?
ab% 

Actually, I don't understand why mine doesn't work, period, since
I can't find anything in the zsh docs saying that it shouldn't...
Any pointers to the place in the zsh docs where this is explained
would be much appreciated.  (I hope that *some day* I'll learn to
find my way around the zsh documentation, but I'm nowhere near that
point yet.)

~kj

[toc] | [prev] | [next] | [standalone]


#4881

Fromkj <no.email@please.post>
Date2012-05-02 19:12 +0000
Message-ID<jns0vn$onv$1@reader1.panix.com>
In reply to#4880
[fixing a typo here]

In <jns0pa$apr$1@reader1.panix.com> kj <no.email@please.post> writes:


>...But now I'm **really** confused.  I don't why the first
                                             ^
                                            get

>subshell below (i.e. your version) terminates upon error but the
>second one (mine) doesn't:

>% ( set -e; printf a; false; printf b ); echo $?
>a1
>% ( set -e; printf a; false; printf b ) || echo $?
>ab% 

>Actually, I don't understand why mine doesn't work, period, since
>I can't find anything in the zsh docs saying that it shouldn't...
>Any pointers to the place in the zsh docs where this is explained
>would be much appreciated.  (I hope that *some day* I'll learn to
>find my way around the zsh documentation, but I'm nowhere near that
>point yet.)

>~kj

[toc] | [prev] | [next] | [standalone]


#4882

FromStephane Chazelas <stephane.chazelas@gmail.com>
Date2012-05-02 20:27 +0100
Message-ID<20120502192715.GG10446@chaz.gmail.com>
In reply to#4880
2012-05-02 19:09:30 +0000, kj:
> 
> First of all, thanks for all the replies!
> 
> In <slrnjq235r.qt6.vaeth@lounge.imp.fu-berlin.de> Martin Vaeth
> <vaeth@mathematik.uni-wuerzburg.de> writes:
> 
> >kj <no.email@please.post> wrote:
> >>
> >> despite the set -e (errexit), the subshell does
> >> not exit on error
> 
> >Here it does (in script and also interactive):
> 
> ># ( set -e; printf a; false; printf b ); echo $?
> >a1
> 
> Thanks.  But now I'm **really** confused.  I don't why the first
> subshell below (i.e. your version) terminates upon error but the
> second one (mine) doesn't:
> 
> % ( set -e; printf a; false; printf b ); echo $?
> a1
> % ( set -e; printf a; false; printf b ) || echo $?
> ab% 
> 
> Actually, I don't understand why mine doesn't work, period, since
> I can't find anything in the zsh docs saying that it shouldn't...
> Any pointers to the place in the zsh docs where this is explained
> would be much appreciated.  (I hope that *some day* I'll learn to
> find my way around the zsh documentation, but I'm nowhere near that
> point yet.)
[...]

It's not specific to zsh.

The effect of "set -e" is cancelled when on the left hand side
of || or && or in and "if", "while" or "until". Basically
everywhere where the exit status is checked. In other words,
when a non-zero exit status is checked as part of a condition.

false

exits the shell. (false fails)

but not

false || true
(false is taken as a condition upon which to execute true or
not)

A side effect is that "set -e" is cancelled for the whole of the
subshell in:

(false; echo still here) || true

It's a bit confusing but that's how all the shells behave.

"|| true" or "|| : ignore errors" is the idiom to say you don't
care about the exit status when "set -e" is in effect.

set -e
command-that-may-fail-but-we-dont-care || : ignore error

-- 
Stephane

[toc] | [prev] | [next] | [standalone]


#4886

Fromkj <no.email@please.post>
Date2012-05-03 18:20 +0000
Message-ID<jnui9j$b8b$1@reader1.panix.com>
In reply to#4882
In <20120502192715.GG10446@chaz.gmail.com> Stephane Chazelas
<stephane.chazelas@gmail.com> writes:

>2012-05-02 19:09:30 +0000, kj:
>> 
>> First of all, thanks for all the replies!
>> 
>> In <slrnjq235r.qt6.vaeth@lounge.imp.fu-berlin.de> Martin Vaeth
>> <vaeth@mathematik.uni-wuerzburg.de> writes:
>> 
>> >kj <no.email@please.post> wrote:
>> >>
>> >> despite the set -e (errexit), the subshell does
>> >> not exit on error
>> 
>> >Here it does (in script and also interactive):
>> 
>> ># ( set -e; printf a; false; printf b ); echo $?
>> >a1
>> 
>> Thanks.  But now I'm **really** confused.  I don't why the first
>> subshell below (i.e. your version) terminates upon error but the
>> second one (mine) doesn't:
>> 
>> % ( set -e; printf a; false; printf b ); echo $?
>> a1
>> % ( set -e; printf a; false; printf b ) || echo $?
>> ab% 
>> 
>> Actually, I don't understand why mine doesn't work, period, since
>> I can't find anything in the zsh docs saying that it shouldn't...
>> Any pointers to the place in the zsh docs where this is explained
>> would be much appreciated.  (I hope that *some day* I'll learn to
>> find my way around the zsh documentation, but I'm nowhere near that
>> point yet.)
>[...]

>It's not specific to zsh.

<helpful explanation snipped>

>It's a bit confusing but that's how all the shells behave.

Hmm... I wonder if this is why the zsh documentation does not mention
this bit of general shell weirdness (AFAICT).

Be that as it may, thanks for the clarification.


In <20120502195328.GH10446@chaz.gmail.com> Stephane Chazelas
<stephane.chazelas@gmail.com> writes:

>2012-05-02 19:33:34 +0000, kj:
>>   http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=520101
>>   http://permalink.gmane.org/gmane.linux.debian.devel.bugs.general/545456
>> 
>> Is this what you have in mind?
>[...]

>No, that's about coding practice, maintainability and
>reliability.

>Relying on "set -e" to do your error handling is a bad idea in
>anything more than the simplest of scripts that just run a
>command after the other.

>- commands can have non-zero exit statuses that don't mean an
>  error (see "test", "expr", "grep"...)
>- subtleties like the one you discovered about where its effects
>  are cancelled
>- interactions with subshells, pipes, background jobs
>- some commands will output errors, some will no, "set -e" will
>  not explain why the script dies.

>You just can't assume it works without having to worry.

>And if you start to worry, it's a lot simpler to do the error
>handling properly.


That's food for thought, thanks.  Maybe it's time to revisit my
approach to error handling in shell scripts...

~k

[toc] | [prev] | [standalone]


Back to top | Article view | comp.unix.shell


csiph-web