Hacker News new | past | comments | ask | show | jobs | submit login
What is TTY? (sobyte.net)
240 points by arunc on Aug 13, 2022 | hide | past | favorite | 40 comments



This is a translation of a Chinese blog[0] without mentioning the origin.

See this tweet [1]

Update: it even didn’t change its example of using original blog’s domain name. [2]

0: https://www.kawabangga.com/posts/4515

1: https://twitter.com/laixintao/status/1558667661420404737

2: > Imagine a scenario where you break into someone’s machine, such as the server where kawabangga.com is located, and you find a way to execute python code inside it, but you can only inject the code into it and execute it without seeing the output, what do you do?


I prefer this: https://www.linusakesson.net/programming/tty/

In fact, the image with the “hardware” and “software” diagrams seems to have been copied directly from that link. I did not see any attribution or acknowledgement.


Hi teddyh, like wey-gu mentioned, I am the author of this original Chinese version post, I think this English version was translated by machine instead of human.

You can see from the original post[0], I add a link, a description and credits to every image that not created by me.

However, I accept all other technical criticism under this threads, I didn't dig deep enough while writing this. I will learn more.

0: https://www.kawabangga.com/posts/4515


It can be good to write things down for yourself, to think them through. But I agree that to actually teach others Linus describes it much better, without the sprinkling of errors this post has.

Like for example the author confuses the terminal for the shell. ctrl-w very much is passed right through to bash.

But the author is correct if the user types "cat\n". Now it's the terminal handling ctrl-w. But note that cat doesn't handle ctrl-a.

It's more complex than the author seems to think.

tl;dr: read the other post, not this one.


> Because Ctrl+W is provided by something called TTY, and the other three are provided by the shell

This is more complicated (or simpler?) than what the article explains. Or I might be really confused. But if you strace bash while typing in stuff, you see clearly that it is reading in characters one by one, including ^W, and handling them itself. I don't see TTY doing much magic here at all:

    read(0, "h", 1)                         = 1
    write(2, "h", 1)                        = 1
    read(0, "e", 1)                         = 1
    write(2, "e", 1)                        = 1
    read(0, "l", 1)                         = 1
    write(2, "l", 1)                        = 1
    read(0, "l", 1)                         = 1
    write(2, "l", 1)                        = 1
    read(0, "o", 1)                         = 1
    write(2, "o", 1)                        = 1
    read(0, " ", 1)                         = 1
    write(2, " ", 1)                        = 1
    read(0, "w", 1)                         = 1
    write(2, "w", 1)                        = 1
    read(0, "o", 1)                         = 1
    write(2, "o", 1)                        = 1
    read(0, "r", 1)                         = 1
    write(2, "r", 1)                        = 1
    read(0, "l", 1)                         = 1
    write(2, "l", 1)                        = 1
    read(0, "d", 1)                         = 1
    write(2, "d", 1)                        = 1
    read(0, "\x17", 1)                      = 1     <-- bash reading in ^W!
    write(2, "\x08\x08\x08\x08\x08\x1b\x5b\x4b", 8) = 8


stracing bash more reveals another thing; when executing command like stty then before forking bash calls TCSETSW ioctl to set tty settings, and after child exists its calls TCSETSW again to set its own values, so stty does not actually show what mode the tty is in while bash is handling the input:

    ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig icanon echo ...}) = 0
    clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fe653abef10) = 5175
    wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WSTOPPED|WCONTINUED, NULL) = 5175
    --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=5175, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
    wait4(-1, 0x7fff156cbad0, WNOHANG|WSTOPPED|WCONTINUED, NULL) = -1 ECHILD (No child processes)
    ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig -icanon -echo ...}) = 0
https://man7.org/linux/man-pages/man4/tty_ioctl.4.html


I wish it would fully reset the terminal mode after every command though so you don't get stuck without seeing what you type when some CUI program terminates without cleaning up properly. That's why I have `stty sane` in my PROMPT_COMMAND.


I believe this is handled by the tty "canonical" (line input) mode. If you run "stty -a" you'll see a number of special characters defined, like werase = ^W

If you set this to something else (stty werase ^O) you'll see it takes effect immediately.


but as it turns out bash does not use canonical mode, and I suspect that applies to many other interactive repls/shells too; probably something readline handles


You are correct for bash. If you run "cat" (from "bash"), you'll see that it no longer handles control-A or control-E (handled by readline...), but control-W is still handled by the tty.


Interesting.

Also if you disable werase i.e. "stty werase ''" and use the bind bash builtin to set "bind Control-w:' backward-kill-word'" you will get slightly different behaviour. A hyphen will be considered a word ending, unlike the tty.

So does bash read ^w and mimics the tty behaviour regarding the definition of a word?

I don't have linux handy right now and tracing on macos is painful otherwise I'd dive deeper.


This is an excellent and entertaining intro to the world of TTYs and I think the first question is a particularly clever way to introduce it:

> The answer is Ctrl+W. Because Ctrl+W is provided by something called TTY, and the other three are provided by the shell.

My only criticism is a pet peeve of mine: screenshots of terminals. I know it's more work to copy/paste and make sure formatting is correct, and you lose the ANSI colors. But it just feels so wasteful and inaccessible (<img alt="tty">).


You can use the script(1) utility (from util-linux) to record a session and it will save the ANSI colors. This only works if you do it ahead of time, though. And if you're putting it in a pastebin, the color codes will get in the way.


There's also https://asciinema.org . It makes recordings which can be replayed just like video (colors and all), but weigh almost nothing and let you select and copy text. There are lots of examples on the main page.


There exists tooling to convert these typescripts into, for example, HTML output to include on your website. I use the script(1) util as part of my dayjob to create a bit of a trail when there are questions later.

Some terminal emulators also support dumping the buffer as HTML.


> There exists tooling to convert these typescripts into, for example, HTML output to include on your website.

Indeed, I mentioned aha in another comment.

> Some terminal emulators also support dumping the buffer as HTML.

That's a nifty feature that I haven't run into yet. Seems like it could be quite useful.


Konsole does HTML export and the HTML is simple/editable (only inline styles, insignificant whitespace removed, output as-shown, not as-generated, so e.g. a progress bar is just a single line of text, not however many times it was updated).


You could preserve the colors with some CSS, even :) I have the sudden urge to write a small tool/some CSS that can automatically convert bits of terminal output into ready-to-use fancy HTML+CSS.


Something like aha? (It's probably in your distro's repo)

https://github.com/theZiz/aha/


I knew that somebody would already have something ready that does this :) Thanks!


Agreed about the intro question, it took me from "I should know more about what tty means (after seeing it for many years)" to "I want to know!"


gnome-terminal has a "Copy as HTML" option which is great for this. It basically generates a <pre> tag with colours and basic styling.


I mean, if someone asked me about this in an interview, I would say something like "As a working software developer, what I can tell you is that sometimes the line discipline gets broken and borks the line endings, and I know how to reset it at that point, and that is the only reason I normally have to think about this particular layer of the whole shell software stack, but if I ever had a professional reason to look into it in more detail, at least I do know where to start digging."


It was probably a good abstraction for its time. The driver for the particular terminal was abstracted away in the OS, meaning that programs only had to handle a pre-defined set of signals and IO.

It is, however, a needlessly complex abstraction as of now. The lack of a real terminal device means that the OS maintains such pseudo devices for the sole purpose of being able to spawn multiple virtual terminals.


But it's a convenient least-common-denominator and abstraction layer for text-mode applications. We might not be using physical teletypewriters now (or VT100-style video terminals), but it's really convenient to be able to write an application once and know that it's going to just work whether I'm running it in a text-mode console or in xterm or in gnome-terminal or over ssh or in tmux within any of those or... Sure, we could come up with some other standard, but the TTY interface is one we already have, with a huge amount of code already written to work with it; why fix what isn't broken?

Contrast this with Windows; until recently, command-line applications there were pretty tightly coupled to the console host that they ran within [1]; this made remoting of command-line applications difficult and means you had to go through extraordinary hoops just to do things like replace the system's console UI with something like ConEmu or run a terminal within something like Visual Studio Code. More recent versions of Windows try to improve this situation, by adding support for Unix-style pseudoterminals [2] (what they call ConPTY) to the console subsystem. And since ConPTY terminals are based around the same standards as TTY terminals on *nix, things like OpenSSH remoting can now "just work", even for existing command line apps on Windows.

[1] See here for some of the gory details of how this works and how it differs from the conventional *nix approach: https://devblogs.microsoft.com/commandline/windows-command-l...

[2] Blog post describing the PTY infrastructure on Windows: https://devblogs.microsoft.com/commandline/windows-command-l...


> why fix what isn't broken?

Its brokenness is debatable, see for example https://lwn.net/Articles/343828/


bash is a bad example for these types of interview questions because, as others have noted, bash disables many of these tty features and handles them in-process.

Another example: The author touches on line discipline, but then makes the mistake of saying "The command is actually stored in the TTY after it is typed and before the Enter key is pressed" This isn't true in bash, or on any modern shells that support line editing features like tab completion.

If you're going to use this for an interview question, I suggest using cat(1) instead -- it will behave as the author suggests.


> Among these 4 shortcuts, there is one that is implemented differently from the others, which one is it?

Ctrl-A vs Ctrl-E vs Ctrl-W vs up arrow. The correct answer is the up arrow and any interviewer who disagrees will walk out of the room with a broken nose. Bash, readline, etc, operate in raw mode so the tty driver isn't handling anything. Three are control characters - a single character. Meanwhile, a vt100 can generate 2 different sequences for the up arrow -- ESC [ A or ESC O A -- depending on cursor key mode. Either way, that's 3 characters instead 1 character. (There's also a third sequence -- ESC A -- in vt52 mode but we'll ignore that).


> Ctrl+B to move a letter forward

Did they mean Ctrl+B to move a letter backward?

Ctrl+F moves a letter forward.


recently i tasked myself into creating a bash TUI library/framework, thinking it would be as easy as taking good old pascal in late 1990s and just drawing on screen using ascii. Boy was I mistaken!


Something like dialog or whiptail? Dialog uses ncurses and whiptail uses s-lang.


yes, but no underlying libs, just pure bash... "How hard can that be"...


PC TUIs have the advantage of direct access to the character buffer. Doing it indirectly with control codes is much more involved when it comes to tracking terminal state.


Using dialog is.. not comfortable - its a great tool, but its hard.


Further evidence that I am so clueless about the workings of many tools I use every day


I mean modern computing is built upon many layers of abstraction, where you only need to understand the technicalities of the thing you're specifically working on, and the tech you don't have time to focus on will seem like "magic" due to abstraction.


Kind of related, Textmode Window Environment is interesting.

https://github.com/cosmos72/twin

A couple screenshots are on the old SourceForge site.

https://sourceforge.net/projects/twin/


I would hope this wasn’t a software engineering interview question. I’ve been in industry a while, and would have no idea what to say if asked about this in an interview.


It would be a good red flag to stay away from that company, unless they were producing something very specific to Unix terminals.


No mention of PuTTY?




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: