zsh-users
 help / color / mirror / code / Atom feed
* Arithmetic Zero
@ 2024-03-05  3:28 sergio
  2024-03-05  4:23 ` Bart Schaefer
  2024-03-05  7:26 ` Roman Perepelitsa
  0 siblings, 2 replies; 5+ messages in thread
From: sergio @ 2024-03-05  3:28 UTC (permalink / raw)
  To: zsh-users


I believe -e is best practices for scripts, so have:

```
#!/bin/zsh -e
(( test = 0 ))
echo $test
```

and it doesn't work of course.

1. What is the reason for returning 1 when an arithmetic evaluation 
succeeds but is zero?

2. How to do arithmetic evaluation properly in zsh sripts? postpend with 
  || true

-- 
sergio.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Arithmetic Zero
  2024-03-05  3:28 Arithmetic Zero sergio
@ 2024-03-05  4:23 ` Bart Schaefer
  2024-03-05  5:02   ` Lawrence Velázquez
  2024-03-05  7:09   ` Stephane Chazelas
  2024-03-05  7:26 ` Roman Perepelitsa
  1 sibling, 2 replies; 5+ messages in thread
From: Bart Schaefer @ 2024-03-05  4:23 UTC (permalink / raw)
  To: sergio; +Cc: zsh-users

On Mon, Mar 4, 2024 at 7:28 PM sergio <sergio@outerface.net> wrote:
>
> I believe -e is best practices for scripts

Leaving opinions aside ...

> 1. What is the reason for returning 1 when an arithmetic evaluation
> succeeds but is zero?

(( ... )) is intended to be useful in tests:
  if (( status == 1 )); then ...

> 2. How to do arithmetic evaluation properly in zsh sripts?

Several choices.
  typeset -i test=0
  : $(( test = 0 ))
  printf -v x "%d" 0

Or (back to opinions) don't use errexit.  IMO it's a band-aid that
discourages properly testing exit status where you should.  Plus, it's
got several obscure bugs in all released versions of zsh, not fixed
until the current development version (as of late 2022).


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Arithmetic Zero
  2024-03-05  4:23 ` Bart Schaefer
@ 2024-03-05  5:02   ` Lawrence Velázquez
  2024-03-05  7:09   ` Stephane Chazelas
  1 sibling, 0 replies; 5+ messages in thread
From: Lawrence Velázquez @ 2024-03-05  5:02 UTC (permalink / raw)
  To: sergio; +Cc: Bart Schaefer, zsh-users

On Mon, Mar 4, 2024, at 11:23 PM, Bart Schaefer wrote:
> On Mon, Mar 4, 2024 at 7:28 PM sergio <sergio@outerface.net> wrote:
>> 1. What is the reason for returning 1 when an arithmetic evaluation
>> succeeds but is zero?
>
> (( ... )) is intended to be useful in tests:
>   if (( status == 1 )); then ...

Put another way, you can think of ((...)) as "translating" C's
notion of true/false into the shell's.  C considers zero-valued
expressions to be false, so ((...)) "translates" them into an exit
status of 1, which the shell considers false/failing.  Similarly,
C considers non-zero-valued expressions to be true, so for those
((...)) returns 0, which the shell considers true/successful.

-- 
vq


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Arithmetic Zero
  2024-03-05  4:23 ` Bart Schaefer
  2024-03-05  5:02   ` Lawrence Velázquez
@ 2024-03-05  7:09   ` Stephane Chazelas
  1 sibling, 0 replies; 5+ messages in thread
From: Stephane Chazelas @ 2024-03-05  7:09 UTC (permalink / raw)
  To: sergio, zsh-users; +Cc: Bart Schaefer

2024-03-04 20:23:51 -0800, Bart Schaefer:
> On Mon, Mar 4, 2024 at 7:28 PM sergio <sergio@outerface.net> wrote:
> >
> > I believe -e is best practices for scripts
> 
> Leaving opinions aside ...
[...]

https://mywiki.wooledge.org/BashFAQ/105
https://fvue.nl/wiki/Bash:_Error_handling
https://mywiki.wooledge.org/BashPitfalls#set_-euo_pipefail

(for bash but most of it applies to other Bourne-like shells)
are good references about the problems with errexit.

One might add that using option names rather than letters is
preferable as more legible (and more portable like for -f vs
noglob where -f means something different in zsh and other
shells), and that it's preferable to set them via "set" rather
than via the shebang as the shebang is not honours when the
script is invoked as zsh path/to/the/script or source
path/to/the/script or zsh < path/to/the/script and on most
systems, shebang can have only one extra argument and using
options there prevents adding the option delimiter.

So:

#! /bin/zsh -
set -o errexit -o nounset -o pipefail

(or setopt if you prefer but I like set -o better as that's
supported by many other shells)

Rather than

#! /bin/zsh -euopipefail

Of those 3 options, nounset is the least controversial. errexit
is a minefield and pipefail can be problematic when using
pipe consumers that exit (successfully) without reading their
whole input (where a death by SIGPIPE of the feeder is not
necessarily a failure.

Best to do proper error handling. I usually define a die
function for that:

die() {
  print -ru2 -C1 -- "$@"
  exit 1
}

cmd1 || die
cmd2 || die "some error message"

-- 
Stephane


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Arithmetic Zero
  2024-03-05  3:28 Arithmetic Zero sergio
  2024-03-05  4:23 ` Bart Schaefer
@ 2024-03-05  7:26 ` Roman Perepelitsa
  1 sibling, 0 replies; 5+ messages in thread
From: Roman Perepelitsa @ 2024-03-05  7:26 UTC (permalink / raw)
  To: sergio; +Cc: zsh-users

On Tue, Mar 5, 2024 at 4:28 AM sergio <sergio@outerface.net> wrote:
>
> ```
> #!/bin/zsh -e
> (( test = 0 ))
> ```
>
> 2. How to do arithmetic evaluation properly in zsh sripts? postpend with
>   || true

When I end up in a situation like this, I use this pattern:

  (( expr, 1 ))

Although the more general patterns works here, too:

  list || true

I never use `set -e`, a.k.a. `setopt err_exit`, on its own, because
its behavior within functions is counter to what I need. In fact, I
don't think I ever wanted this option to behave the way it does in
functions. Let me show what I mean.

    set -e
    false
    launch-missiles

If you put these lines at the top level of a zsh script,
launch-missiles won't execute because the previous command (false)
fails. But if you put the same code in a function, this guarantee is
lost.

  % zsh -fc '
    foo() {
      set -e
      false
      print launch missiles
    }

    if ! foo; then :; fi
    foo || false
    foo && true
    print the end'

The output:

  launch missiles
  launch missiles
  launch missiles
  the end

This issue can be solved by turning on err_return together with err_exit.

  foo() {
    setopt local_options err_return err_exit
    false
    launch-missiles
  }

Now, we can either handle errors from the function gracefully:

  if ! foo; then
    do-something
  fi

Or we can let it take the default error handling action, which is to
exit the script:

  foo

In no case will the missiles launch.

Roman.


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2024-03-05  7:28 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-05  3:28 Arithmetic Zero sergio
2024-03-05  4:23 ` Bart Schaefer
2024-03-05  5:02   ` Lawrence Velázquez
2024-03-05  7:09   ` Stephane Chazelas
2024-03-05  7:26 ` Roman Perepelitsa

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).