nushell icon indicating copy to clipboard operation
nushell copied to clipboard

Throw exception on nonzero exit code

Open notramo opened this issue 3 years ago • 7 comments

Related problem

One of the most powerful features of the Elvish shell is that it throws an exception when a program exits with non-zero. For those few programs that returns nonzero even in normal operation (e.g. diff), catching exceptions is easier than doing manual error checking every time for every line of code.

Exceptions could be utilized in other parts of the language too (throw command for usage by the programmer, type errors, etc.).

Describe the solution you'd like

Copy the exception feature of the Elvish shell.

Describe alternatives you've considered

No response

Additional context and details

No response

notramo avatar Apr 27 '22 20:04 notramo

The problem with that is that non-zero exit codes from externals are not always errors.

fdncred avatar Apr 27 '22 21:04 fdncred

If you want to read up on how this difficulty due to the messy reality of exit codes pops up (during nushell's development), you can check out JT's blog post on that https://www.jntrnr.com/exit-codes/

sholderbach avatar Apr 27 '22 21:04 sholderbach

@fdncred Please read previous comments before commenting. And please take a look at how Elvish does this before contributing to the discussion. Your comment didn't help anything.

The problem with that is that non-zero exit codes from externals are not always errors.

Elvish can handle that too. I am using Elvish as a daily driver, and this functionality is one of the most useful. This is what keeps me from switching to Nushell.

https://elv.sh/ref/language.html#exception-capture https://elv.sh/ref/language.html#try Also, exceptions are mentioned in other parts of the documentation, search for "exception" in that page.

notramo avatar Apr 28 '22 08:04 notramo

As far as I understand, this is supposed to work, see #3858

flying-sheep avatar May 11 '22 09:05 flying-sheep

Any news on this? #3858 was closed without any advancement.

ClementNerma avatar Feb 13 '23 09:02 ClementNerma

Mhh we seem to properly suppress the non-zero exit code with try. But we do not return some easily digestable error, that can be processed in catch.

And ; sequences react to the non-zero exit.

/home/stefan/nushell〉try { diff }; echo test
diff: missing operand after 'diff'
diff: Try 'diff --help' for more information.
test
/home/stefan/nushell〉diff; echo test
diff: missing operand after 'diff'
diff: Try 'diff --help' for more information.

sholderbach avatar Feb 13 '23 10:02 sholderbach

Great! This makes sense given these use cases:

  1. I use an external command that happens to write to stderr. I want to see that stream as it appears.
  2. I use an external command that can fail. I want my script to behave sanely and abort unless I use try.

For the following use case, we have do -c!

  1. I run an external command that only writes to stderr when it fails. I want to propagate that as an error message in case of failure
〉do -c { diff }
Error: nu::shell::external_command (link)

  × External command failed
   ╭─[entry #11:1:1]
 1 │ do -c { diff }
   ·         ──┬─
   ·           ╰── External command failed
   ╰────
  help: diff: fehlender Operand nach »diff«
        diff: »diff --help« gibt Ihnen mehr Informationen.

And for this last use case, we have do -s { … } | complete:

  1. I run an external command where “exit status ≠ 0” doesn’t mean failure and I want to handle that:
〉do -s { LANG=C diff /etc/profile.d/jre.sh /etc/profile.d/jre.csh } | complete
╭───────────┬──────────────────────────────────────────────────╮
│ stdout    │ 3,4c3                                            │
│           │ < append_path '/usr/lib/jvm/default/bin'         │
│           │ < export PATH                                    │
│           │ ---                                              │
│           │ > setenv PATH "${PATH}:/usr/lib/jvm/default/bin" │
│           │                                                  │
│ stderr    │                                                  │
│ exit_code │ 1                                                │
╰───────────┴──────────────────────────────────────────────────╯

I’m not sure why do -i { … } | complete swallows the exit code, but this should be good. We just need to have more extensive documentation for 1. all these use cases and 2. the different kinds of errors do can handle, but everything should be good now!

flying-sheep avatar Feb 13 '23 11:02 flying-sheep

I think it would be nice (though I don't know how the implementation would go) if do -i and do -c would preserve the exit code in some way, or if there was a separate flag that did that. My use case is that I want the numeric exit code from an external command, but don't want to use complete as it prevents streaming the stdout.

Zoybean avatar Feb 27 '24 03:02 Zoybean

You can use $env.LAST_EXIT_CODE for that I think: https://www.nushell.sh/book/stdout_stderr_exit_codes.html#exit-code

flying-sheep avatar Feb 27 '24 08:02 flying-sheep

The example given in the book doesn't work in scripts for me - if the code is non-zero, it counts as an error and quits the script:

> def nonzero [] {
  print "start"
  do {bash -c false}
  print $env.LAST_EXIT_CODE
  print "end"
}
> nonzero
start

Zoybean avatar Feb 27 '24 11:02 Zoybean

if you use complete you can get the exit code. I typically use -i to ignore errors.

❯ do -i { bash -c false } | complete
╭───────────┬───╮
│ stdout    │   │
│ stderr    │   │
│ exit_code │ 1 │
╰───────────┴───╯

fdncred avatar Feb 27 '24 14:02 fdncred

@fdncred please see my earlier comment:

I think it would be nice (though I don't know how the implementation would go) if do -i and do -c would preserve the exit code in some way, or if there was a separate flag that did that. My use case is that I want the numeric exit code from an external command, but don't want to use complete as it prevents streaming the stdout.

tl;dr I need the streaming stdout so I can't use complete, and I need the exit code so I can't use do -i or do -c or try-catch

Zoybean avatar Feb 28 '24 05:02 Zoybean

I guess we'd have to have a list of exit codes. Not sure I'm a fan of that.

fdncred avatar Feb 28 '24 12:02 fdncred