elvish
elvish copied to clipboard
Unexpected exception when exiting with 0 after CTRL+C
There's a difference I've noticed with bash
and elvish
that I can't quite explain. I wonder if this is intentional or not.
I'm trying to write a command that runs in the foreground and that can be quit at any time using CTRL+C. Doing so is not an error, it's just a way of interrupting a procedure early (i.e. we set a certain condition in our network and either wait until the timer runs out or stop the condition early if we can).
It's written in Rust, but the behavior can be reproduced with the following Python script:
import signal
import sys
from threading import Event
interrupt = Event()
def quit(*args, **kwargs):
interrupt.set()
sys.exit(0)
for sig in (signal.SIGTERM, signal.SIGHUP, signal.SIGINT):
signal.signal(sig, quit)
print("Waiting for 10s, or until CTL+C is hit")
interrupt.wait(10)
print("Done")
If I run this in bash
or zsh
, I get the following output:
$ python3 test.py
Waiting for 10s, or until CTL+C is hit
^Cbash-5.1$ echo $?
0
$ python3 test.py && echo success
Waiting for 10s, or until CTL+C is hit
^Csuccess
In elvish, I get the following
~ python3 test.py
Waiting for 10s, or until CTL+C is hit
^CException: interrupted
[tty 14], line 1: python3 test.py
~ python3 test.py; echo success
Waiting for 10s, or until CTL+C is hit
^CException: interrupted
[tty 15], line 1: python3 test.py; echo success
Is this a deliberate design decision or am I missing something? It looks like bash
just uses the exit code that the process returns (which seems to default to a zero), while elvish
sees the CTRL+C and fails in any case.
Hmm, I believe this is because Elvish itself is also catching the signal. I consider this a bug.
This is related to job control and how Ctrl-C (SIGINT from the tty) affects background jobs. While I still firmly believe Elvish does not need to implement full support for POSIX job-control (specifically, support for Ctrl-Z and the fg
and bg
commands) it does need to correctly handle Ctrl-C.
@href wrote
It looks like bash just uses the exit code that the process returns (which seems to default to a zero),
That is sort of true. Every UNIX program has an exit status. With zero meaning "no problems" and non zero values indicating a problem of some sort. UNIX programs can explicitly exit with a non-zero status by calling exit()
(or related function) or returning from the main
function with a non-zero value. The basic idea, dating back to to the original UNIX programs from the 1970's, is that a zero exit status meant "success" while a non-zero exit status meant a failure of some sort. POSIX shells like bash simply expose the exit status. Elvish treats a non-zero exit status as an indication of of significant problem that needs to be explicitly handled.