Hacker News new | ask | show | jobs
by M9HF8wwiaAdZKEZ 1419 days ago
> it should interrupt the current computation and let you resume your work without exiting the application

That's not what Ctrl+C is meant for or used for. It's used to terminate the running application, not the running task within that application.

If you want to be able to "resume your work" then you should press Ctrl+Z.

If you want something else then the application should probably be listening for some other keystroke. "Catch Ctrl+C and do something else" is a pretty awful idea for the very reason mentioned at the top of TFA (when you press Ctrl+C, it's to get out of whatever you're stuck in, so that you don't have to go open another terminal and type in killall ...)

4 comments

> That's not what Ctrl+C is meant for or used for. It's used to terminate the running application, not the running task within that application.

I spend a lot of time running computations in REPL, and sometimes I realise that I made a mistake and I don't want to wait for the current operation to complete, or the mistake itself is such that the operation will complete only after I become old and die. In this case, I expect Ctrl+C to abort the current computation and return to the REPL, with the previous state (all the variable assignments) intact (modulo assignments made inside the loop I killed). I think a lot of people have the same expectation, and it's usually satisfied in modern REPLs.

> That's not what Ctrl+C is meant for or used for. It's used to terminate the running application, not the running task within that application.

If that's not how it should behave, how come any REPL I have handy handles Ctrl-C the exact same way? i.e. it doesn't exit the interpreter, it gets me back to the REPL. You can try yourself by getting stuck in a while loop and pressing Ctrl-C

Python (3) does it;

jshell does it;

guile does it;

csi (chicken scheme) does it;

sbcl does it;

bash does it

Because they either fork their processes so the running task is it’s own process (which is how classic shells, like Bash, work) or they capture ^c and interpret it to behave like the classic shells do because that’s the behaviour people expect from shells.

You have to remember that Bash isn’t a language like Python in the sense that it’s core libraries are built into the Python runtime. in classic shells like bash literally every command is an executable. Granted they’ll ship some “builtins” but they’re still invoked via fork() to behave like external commands. So literally every ‘if’, ‘echo’ and ‘for’ (etc) has its own process ID in Linux/UNIX. Thus you can ‘kill’ an ‘echo’.

> or they capture ^c and interpret it to behave like the classic shells do because that’s the behaviour people expect from shells.

Which is kinda the point.

> So literally every ‘if’, ‘echo’ and ‘for’ (etc) has its own process ID in Linux/UNIX. Thus you can ‘kill’ an ‘echo’.

Do they? Because if I try like this `while :; do echo; done` and in another terminal I do `ps -x --forest` I can see the original bash running but it doesn't have any child process.

Besides, is it relevant to the discussion at hand?

> Which is kinda the point.

I thought I’d get picked up on that part. My point was that shells are just a UI for invoking other applications (like a desktop shell but CLI). That’s the precedence and anything that’s shell-like but doesn’t follow POSIX is still inclined to emulate the same behaviour of killing applications because that’s the behaviour that people expect after decades of POSIX.

So it really is more about killing applications than killing tasks.

> Do they?

That was the original design (there’s even standalone executables for those commands included in coreutils for historic reasons). However Bash might have since optimised out a few forks.

The shell I’ve written certainly doesn’t fork() every built in either. However that doesn’t change how ^c’s behaviour was intended.

> Besides, is it relevant to the discussion at hand?

I’m talking about the behaviour for ^c and how it is handed in the shell, as a direct response to your comment about it. So yes. It’s exactly relevant to the discussion.

> So literally every ‘if’, ‘echo’ and ‘for’ (etc) has its own process ID in Linux/UNIX

echo: yes

if, for: no

Control flow statements do not execute in subshells (processes) unless explicitly told to do so.

You may be thinking of test(1) aka [

   if [ a == b ] ; then ....
which was originally written:

   if test a == b ; then
test(1) is its own executable. But [ is a builtin command and does not execute in a separate process.
If the application is a shell or REPL (an application running other programs) then that is exactly what you want to use CTRL-C for.
You might have killed enough programs with Ctrl-C, but SIGINT is an interrupt, not a kill, terminate or quit.