quitting in the terminal

wizard zines
@b0rk hey there, can you help people who are unable to exit vim after ages? 🙂

@KMohZaid what do you mean? I can never tell if "I can't quit vim" is a joke or serious, like I kind of assume that if people are confused about how to quit vim they can google it and see that you can do something like “ESC :qa!" to get out.

but maybe that’s wrong? my brain might be distorted from using vim for too long :)

@b0rk i was talking about meme 😅
@b0rk @KMohZaid I don't believe there is a "too long" for using vim. 🙃
@mafe @b0rk he meant about vim not neovim

@KMohZaid @b0rk

ZQ - exit without saving
ZZ - save and exit

@lulu @b0rk haha yes I sent this as separate reply. Learnt recently
@KMohZaid @b0rk Install neovim, hit ctrl+c and read the message that tells you how it's done. 😉
@mafe @b0rk yes I use it, said about vim because people will try vim before learning neovim. So if they can escape vim, they can get trap in neovim

@b0rk Stubborn programs get a

Ctrl-Z
bg
kill -9 %1

@colin_mcmillen @b0rk absolutely this. I run into this on macOS + zsh all. The. Time. I’ve not dug into why, but I even have a ctrlc_reset=‘trap true INT && trap INT’ (pure cargo cult code from stackexchange) to get ^C working again. Long since lost track of the number of times I’ve needed to ^Z + bg to get out of a program, tho.
@colin_mcmillen @b0rk agreed, I do the ctrl-z kill dance all the time when ctrl-c is not fast or working good enough
@bagder @colin_mcmillen @b0rk Since I'm invariably running in a tmux session, it's `ctrl-b x` for me.

@colin_mcmillen @b0rk I generally use

ctrl-z
kill %%

@b0rk Didnt't know all the possibilites, thanks!
@b0rk TIL about the C→3→SIGINT mapping!

@dngrs @b0rk A tiny technical caveat: control-C sends a byte with value 0x03 on purpose; this is designed into ASCII; the control key maps A through Z to control codes 1 through 26 in alphabetical order; yes, this is why control-[ is another way to type the ESC key.

But the "character code 0x03 means send SIGINT" rule is adjustable (with the `stty` command) and SIGINT itself is usually *not* signal number 3 (there's no official rule for which signals have which numbers, but SIGINT is almost always number 2).

@zwol @dngrs thanks, I need to be better about clarifying which parts of this are configurable and which parts aren't

I think the rules are

* you *can* sometimes configure what `alt` or `option` do in your terminal emulator
* you *can’t* configure what byte `Ctrl+C` will send
* you *can* configure what `3` does (via stty like you said)
* if your terminal emulator sends an escape code (via alt+x, mouse, etc), you usually *can't* configure how the program will handle those escape codes
* ???

@b0rk @dngrs stty also lets you change _which byte_ will send SIGINT (and SIGQUIT and SIGTSTP), like if you want Ctrl-\ (0x28) to mean SIGINT instead of SIGQUIT you can do that. It doesn't even have to be a control code! But setting it to any graphic character or to ^@ ^H ^I ^J ^L ^M ^? ESC or SPACE is liable to have undesirable side effects. This is probably too much detail for the zine I'm just brain dumping.

Some programs do let you configure how the escape codes are handled but it's gonna be program by program and you will have to dig through the manual to find out if it's possible. Because this was the jargon back in the 1970s and it stuck, the term to look for in the manual is often "key binding" or "key rebinding".

I can't think of anything else right now.

@zwol @b0rk @dngrs re. graphic characters, a weird historical thing is that bell labs era unix used # to delete a character and @ to delete a line - the stty erase and stty kill characters that are these days usually ^? and ^U

https://man.freebsd.org/cgi/man.cgi?query=tty&sektion=4&apropos=0&manpath=Unix+Seventh+Edition

and nowadays its rare to encounter tty cooked mode unless typing directly into cat

tty(4)

@fanf @b0rk @dngrs Oh that's a good point. I actually have no idea if readline / editline / vi / etc pay attention to what the terminal thinks the special characters are.

You're in tty cooked mode whenever you need to SIGINT or SIGTSTP a long-running program that doesn't talk to the terminal, though.

I remember # for erase and @ for kill line being mentioned in a 1980s guide to programming microcomputers (think original IBM PC) in cut-down C — there was one chapter of "here's all the stuff Unix 7 C has that Lattice C had to leave out" and of course then had to orient you to the shell a little bit first. I imagine they date to the very earliest days when everyone was stuck using printing terminals.

@zwol @dngrs @b0rk I'd like to link this [1] here since it does a great job of explaining the relation between keys and codes, for whomever is curious about this. (It also claims that Ctrl+C has no relation to ETX which would explain why SIGINT isn't signal number 3)

[1] http://www.catb.org/~esr/faqs/things-every-hacker-once-knew/#_ascii

Things Every Hacker Once Knew

@dandels @dngrs @b0rk ugh, please don't ever link people to references written by Eric Raymond. They are consistently only about 2/3 accurate, plus 1/3 *egregiously wrong*, with the wrong bits tangled up with the accurate bits so thoroughly that it's hopeless to try to sort them out
@zwol do you know of any accurate reference? one thing I noticed with that one is that (on my machine) Ctrl+H is not backspace but it wasn't obvious why not, since I think I've been on other machines where Ctrl+H was backspace

@b0rk Unfortunately, not for the stuff covered by that one. I have occasionally been tempted to write my own version but it would be so much tedious fact-checking that I probably won't ever do it unless someone wants to pay me to do it.

The backspace key nowadays almost always sends ^? to the software running in the terminal (ASCII DEL, 0x7F). However, a long time ago (I remember this being a Thing in the 1990s), depending on which terminal (emulator) you had and how it was connected to the computer (actual serial line, ssh, rlogin, telnet, local pseudoterminal pair, etc) there was a good chance backspace would send ^H (ASCII BS, 0x08) instead. I never knew how to predict which I'd get.

(On terminals that used ^H for backspace, the delete key, if there was one, would usually send ^?. Nowadays, with ^? being used for backspace, the delete key sends ESC [ 3 ~ instead (no spaces).)

@b0rk The *idea* of the `stty erase` configuration knob is that the software that runs first thing when you start a terminal connection (specifically, in the olden days this was the `getty` program's responsibility) is supposed to figure out what kind of terminal is at the other end of the line, and in particular what control codes it sends for backspace, and then set the configuration knobs so that when you use the backspace key it works correctly. But there are a lot of ways this process can go wrong, so the stty command lets you fix it by hand.
@zwol i started trying to make my own this morning but it's really a mess and has a million mistakes, and who handles what seems to depend on so many things (raw vs cooked, stty, probably more)

@b0rk it really is such a giant mess

notes off the top of my head mostly about readline:

- Character 0 should be spelled NUL, not NULL (this is a historical quirk of the ASCII spec, reused nowadays to distinguish it from C's NULL *pointer*). It is sent by Ctrl-@ and usually also Ctrl-SPACE.

- Readline's meaning for Ctrl-K is 'delete text from cursor position to the end of the line' and for Ctrl-U it's 'delete text from cursor position to the beginning of the line'. This is important if you have the cursor somewhere in the middle of the line.

- The terminal driver also understands Ctrl-U; for the terminal driver it technically means "delete the whole line" but because you *can't* have the cursor in the middle of a line if the terminal driver is what's processing control keys, it's functionally the same thing as readline

- Readline does have a meaning for Ctrl-T, it is "swap the characters right before and after the cursor", unless the cursor is at the end of the line, then it's "swap the two characters right before the cursor." It's for fixing typos. Examples: type "sl" and then Ctrl-T, you'll now have "ls". Type "pyhton", put the cursor on the t, Ctrl-T, you'll now have "python".

- If you turn off pause/unpause as discussed in earlier threads, then readline will make Ctrl-Q be the same as Ctrl-V, and Ctrl-S be "search *forward* from where we are in history search", which is handy if you typed Ctrl-R a few too many times.

- Readline _also_ has a meaning for Ctrl-_: "undo" (character by character, I think).

- The reason readline *doesn't* have a meaning for Ctrl-X is that Emacs uses that key as a prefix for another set of keybindings (e.g. in emacs C-s means search forward in the file but C-x C-s means save the current file).

- all the readline keybindings are documented in "man readline" and can be configured in a dotfile, "~/.inputrc". you can even switch it over to acting like cut-down vi rather than cut-down emacs if you want.

@zwol Hm, alright, I'll keep this in mind. Alas, finding quality sources is hard.
@b0rk I was going to suggest a zine on how to quit vim but it might need an entire encyclopaedia.

@b0rk

Apropos of that:

If you've used ctrl-z to suspend a program but haven't put it in the background with bg, many versions of bash will warn you about it the first time you try to exit with ctrl-d (or exit). That's helpful, because maybe you weren't done with that program.

It happens more often than I'd like that I can't quit [some program] because ... I am looking at a screenshot of [that program].

The way ctrl-\ gets turned into a signal is very similar to ctrl-c

@b0rk Huh. That made me realise that I haven't seen anything that required F10 to exit in a loooooooong time.

@b0rk Great work! I never digged into why Ctrl-D works and this explains it well!

Though I am confused about the description that terminal sends SIGINT for ctrl-C because C is the third letter in the alphabet. That doesn't happen to any other letters. For example, Ctrl-A doesn't generate a signal

@lesley yeah Ctrl-A sends the number `1` to the OS terminal driver but `1` isn't translated into a signal the way `3` is, `3` is special.

`1` is just passed through to the program, so if you type Ctrl-A the program will just get a `1` byte.

@b0rk @lesley You probably know this or saw it while making this page, but I just learned: that ^C = 3 = SIGINT = exit doesn't mean anything, it's just a random reuse of the ETX code started by DEC (although: "citation needed") https://en.wikipedia.org/wiki/End-of-Text_character

^D = EOT = End Of Transmission seems more logical! https://en.wikipedia.org/wiki/C0_and_C1_control_codes

End-of-Text character - Wikipedia

@ednl interesting, what do you mean by “doesn't mean anything"?

I’d assume that 3 = SIGINT is standardized somewhere (maybe POSIX???) though I don't know where

@b0rk That there is no, or doesn't seem to be, a semantic meaning, it was just a random pairing. Except maybe it *was* logical to DEC (on the PDP-11 presumably?) but I couldn't find that.

@ednl I guess I don't really understand how the number 3 could have a semantic meaning?

like choosing what 3 should do seems arbitrary in the first place and I don't understand why what "3" does on my computer today would necessarily be related to what a different arbitrary standard from the past decided "3" should mean

(probably what's going on is that there's some "important" standard here that I don't realize is important)

@ednl oh I get it, I think you're saying that a lot of control characters in ASCII have a name, and a lot of the time the name is related to what it does today (like "bell" or "line feed") but also sometimes it doesn't

sorry I'm slow :)

@b0rk Yes. I mean no, you're not slow :) I was too concise! The name is the most obvious logical connection, but also I think the first reply you replied to was looking for a deeper meaning of the number 3 "why would that be a SIGINT?" But there just doesn't seem to be a logical or semantic connection, it randomly came together (and apparently at DEC).

I always thought C stood for Cancel but that's probably an explanation after the fact. My own folk etymology!

@b0rk I feel like it might be worth trying to squeeze "Ctrl-Z and then kill %%" into the "ways to quit" box as another thing that sometimes works when Ctrl-C doesn't

nowadays this feature is almost always turned off by default, but Ctrl-\ *might* drop a large and mostly useless file named "core" in the directory you're in, as a side effect; this doesn't need to be on the page you're showing but if there's a "weird side effects of quitting" page then it should go there

@b0rk I saw a reply go by asking if there was anything that would _always_ work, and I was going to answer but then the reply disappeared, but I think the answer might be worth mentioning somewhere (again probably not on this page):

`kill -9 <process-ID>` (on modern computers, you can also type `kill -KILL`, but I'm old and `kill -9` is what's wired into my fingers) is guaranteed to work *as long as it's the program itself that's suppressed all other ways of quitting*, but you have to be able to get another shell prompt to use it. It may cause data loss (it's effectively "force quit without saving first", whereas ^C and ^D and so on do give the program a chance to save files on the way out) and it might leave the terminal in a messed-up state.

Sometimes you have to do `kill -CONT <process-ID>` as well to make the kill -9 work. I don't fully understand when this is necessary, it's just tripped me a few times.

In rare circumstances -- the most common being that the program is stuck trying to talk to a network file server that's down -- it *isn't* the program itself that's preventing quitting, but the kernel, and then you may have no recourse whatsoever short of rebooting the entire computer.

@b0rk This might be a bit too in the weeds, but Ctrl-D flushes the current terminal line buffer. EOF is commonly detected by having a zero-length read, so you can also exit without having a newline by doing Ctrl-D twice (once to flush the current line, and once to trigger a zero-length read). I tested this to verify I remembered it correctly and doesn't work for a Python REPL, but works for `cat > foo.txt` or similar.
@light thanks! i want to figure out why it doesn’t work for python, maybe it’s related to readline somehow
@b0rk That would be my guess as well. 👍
@b0rk years of SSH over flakey connections has graven tilde + period into my brain, purely to offer another common and needlessly unique escape and quit sequence
@b0rk and sometimes Ctrl-G helps if you find yourself stuck within Emacs...
@b0rk This obviously means that we need an editor which follows the standard and uses q as the quit key, since its a fullscreen application.

@BafDyce

In case you missed it, the `micro` text editor uses these sorts of mappings

@b0rk

@b0rk @bagder though a very special yet common case, ENTER~. (enter tilde period) has proven a very useful sequence to exit hung SSH sessions
@b0rk I love how simple this is. Perfect explanation.
@b0rk I recently met someone who used Ctrl-q instead of q to quit full screen program. It seemed natural for him, and I can't blame him for this. But he piled up a list of stopped processes in his session. 😞