this post was submitted on 20 Mar 2025
37 points (75.3% liked)

Linux

52158 readers
874 users here now

From Wikipedia, the free encyclopedia

Linux is a family of open source Unix-like operating systems based on the Linux kernel, an operating system kernel first released on September 17, 1991 by Linus Torvalds. Linux is typically packaged in a Linux distribution (or distro for short).

Distributions include the Linux kernel and supporting system software and libraries, many of which are provided by the GNU Project. Many Linux distributions use the word "Linux" in their name, but the Free Software Foundation uses the name GNU/Linux to emphasize the importance of GNU software, causing some controversy.

Rules

Related Communities

Community icon by Alpár-Etele Méder, licensed under CC BY 3.0

founded 5 years ago
MODERATORS
 

Honestly I had no idea what ctrl+d even did, I just knew it was a convenient way for me to close all the REPL programs I use. The fact that it is similar to pressing enter really surprised me, so I wanted to share this knowledge with you :)

all 19 comments
sorted by: hot top controversial new old
[–] davel@lemmy.ml 23 points 2 days ago* (last edited 2 days ago) (2 children)

CTRL+M is like pressing ENTER. Kernigan & Pike, 1984: UNIX Programming Enviornment

RETURN is an example of a control character — an invisible character that controls some aspect of input and output on the terminal. On any reasonable terminal, RETURN has a key of its own, but most control characters do not. Instead, they must be typed by holding down the CONTROL key, sometimes called CTL or CNTL or CTRL, then pressing another key, usually a letter. For example, RETURN may be typed by pressing the RETURN key or, equivalently, holding down the CONTROL key and typing an ‘m’. RETURN might therefore be called a control-m, which we will write as ctl-m.

[–] tuna@discuss.tchncs.de 9 points 2 days ago

On any reasonable terminal, RETURN has a key of its own

This reminds me of a time at work when I was not on a reasonable terminal. I was explaining to a co-worker how I automated some tasks by running some scripts, but in my demo my RETURN key didn't work, so I had to improvise and use CTRL+M which worked, hahaha. I don't know how the terminal got in such a bad spot but it was probably something to do with msys on Windows.. honestly not sure. It was perfect timing to have happen while teaching of course ;)

I would also be doing a disservice not to share what the book you linked says about CTRL+D. Right after your quote, it says:

Other control characters include ctl-d, which tells a program that there is no more input

This is pretty good for an introduction, but it is not the full story. It explains CTRL+D properly later (chapter 2, page 45):

Now try something different: type some characters and then a ctl-d rather than a RETURN:

$ cat -u
123<ctl-d>123

cat prints the characters out immediately. ctl-d says, “immediately send the characters I have typed to the program that is reading from my terminal.” The ctl-d itself is not sent to the program, unlike a newline. Now type a second ctl-d, with no other characters:

$ cat -u
123<ctl-d>123<ctl-d>$

The shell responds with a prompt, because cat read no characters, decided that meant end of file, and stopped. ctl-d sends whatever you have typed to the program that is reading from the terminal. If you haven’t typed anything, the program will therefore read no characters, and that looks like the end of the file. That is why typing ctl-d logs you out — the shell sees no more input. Of course, ctl-d is usually used to signal an end-of-file but it is interesting that it has a more general function.

This is why the article says it's "like pressing enter," because it flushes the input just like enter. The difference is that enter sends a newline, but CTRL+D does not, so you can exploit that to send no data (and the program chooses to interpret that as an EOF).

[–] Ferk@lemmy.ml 6 points 2 days ago* (last edited 2 days ago)

Yes, although Ctrl-M would be the "Carriage Return" character (\r). For the "Line Feed" newline character (\n) the Control combination would be Ctrl-J. Both of them would normally produce a new line when you press them on most terminals.

That's why if you open in nano/vim a file with Windows style EOL (/r/n), you might see a strange ^M symbol at the end of each line.

[–] mina86@lemmy.wtf 20 points 2 days ago* (last edited 2 days ago) (2 children)

It’s not. You keep insisting that ^D doesn’t send EOF and yet:

$ stty -a | grep eof
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
$ man stty |grep -A1 eof |head -n2
       eof CHAR
              CHAR will send an end of file (terminate the input)

^D is the EOF character. The thing is that in C every line of a text file must be terminated by a new-line. And so, when you end a file with ^D without a return, you get funky results.

[–] Ferk@lemmy.ml 8 points 2 days ago

To be more precise, it's the "EOT" (end of transmission) control character, the 4th symbol in ASCII, from the non-printable character area.

[–] cypherpunks@lemmy.ml 4 points 1 day ago* (last edited 1 day ago) (1 children)

Note: for readers who aren't aware, the notation ^X means hold down the ctrl key and type x (without shift).

ctrl-a though ctrl-z will send ASCII characters 1 through 26, which are called control characters (because they're for controling things, and also because you can type them by holding down the control key).

^D is the EOF character.

$ stty -a | grep eof
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
$ man stty |grep -A1 eof |head -n2
       eof CHAR
              CHAR will send an end of file (terminate the input)

Nope, Chuck Testa: there is no EOF character. Or, one could also say there is an EOF character, but which character it is can be configured on a per-tty basis, and by default it is configured to be ^D - which (since "D" is the fourth letter of the alphabet) is ASCII character 4, which (as you can see in man ascii) is called EOT or "end of transmission".

What that stty output means is that ^D is the character specified to trigger eof. That means this character is intercepted (by the kernel's tty driver) and, instead of sending the character to the process reading standard input, the tty "will send an end of file (terminate the input)".

By default eof is ^D (EOT), a control character, but it can be set to any character.

For instance: run stty eof x and now, in that terminal, "x" (by itself, without the control key) will be the EOF character and will behave exactly as ^D did before. (The rest of this comment assumes you are still in a normal default terminal where you have not done that.)

But "send an end of file" does not mean sending EOT or any other character to the reading process: as the blog post explains, it actually (counterintuitively) means flushing the buffer - meaning, causing the read syscall to return with whatever is in the buffer currently.

It is confusing that this functionality is called eof, and the stty man page description of it is even more so, given that it (really!) does actually flush the contents of the buffer to read - even if the line buffer is not empty, in which case it is not actually indicating end-of-file!

You can confirm this is happening by running cat and typing a few characters and then hitting ^D, and then typing more, and hitting ^D again. (Each time you flush the buffer, cat will immediately echo the latest characters that had been buffered, even though you have not hit enter yet.)

Or, you can pipe cat into pv and see that ^D also causes pv to receive the buffer contents prior to hitting enter.

I guess unix calls this eof because this function is most often used to flush an empty buffer, which is how you "send an end of file" to the reader.

The empty-read-means-EOF semantics are documented, among other places, in the man page for the read() syscall (man read):

RETURN VALUE
      On success, the number of bytes read is returned (zero indicates end of
      file), and the file position is advanced by this number.

If you want to send an actual ^D (EOT) character through to the process reading standard input, you can escape it using the confusingly-named lnext function, which by default is bound to the ^V control character (aka SYN, "synchronous idle", ASCII character 22):

$ man stty|grep lnext -A1
       * lnext CHAR
              CHAR will enter the next character quoted
$ stty -a|grep lnext
werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;

Try it: you can type echo " and then ctrl-V and ctrl-D and then "|xxd (and then enter) and you will see that this is sending ascii character 4.

You can also send it with echo -e '\x04'. Note that the EOT character does not terminate bash:

$ echo -e '\x04\necho see?'|xxd
00000000: 040a 6563 686f 2073 6565 3f0a            ..echo see?.
$ echo -e '\x04\necho see?'|bash
bash: line 1: $'\004': command not found
see?

As you can see, it instead interprets it as a command.

(Control characters are perfectly cromulent filenames btw...)

$ echo -e '#!/bin/bash\necho lmao' > ~/.local/bin/$(echo -en '\x04')
$ chmod +x ~/.local/bin/$(echo -en '\x04')
$ echo -e '\x04\necho see?'|bash
lmao
see?

[–] mina86@lemmy.wtf 2 points 16 hours ago

Which is why I haven’t wrote ‘EOF character’, ‘EOT’ or ‘EOT character’. Neither have I claimed that \x4 character is interpreted by the shell as end of file.

[–] double_quack@lemm.ee 18 points 2 days ago* (last edited 2 days ago) (1 children)

Ctl-D is the End-of-File character. Programs interpret it as "that's it, the input you were reading has finished", and react accordingly.

[–] tuna@discuss.tchncs.de 3 points 2 days ago (2 children)
$ cat
You sound very nice :)
You sound very nice :)
Bye<ctl-d>Bye

Oh wait, and cool too
Oh wait, and cool too
<ctl-d>
$ 

The Ctl-D didn't end the file when i typed "Bye" :( it only worked when I pressed Ctl-D on its own line. So how does cat know that it should ignore the EOF character if there is some text that comes before it?

What Ctl-D does is flush the input to the program, and the program sees how big that input is. If the length of the input is 0 that is interpreted as EOF. So Ctl-D is like Enter because they both flush the input, but Ctl-D is unlike Enter because it does not append a newline before flushing, and as a consequence you can send empty input (aka an EOF "character") with Ctl-D.

[–] CasualTee@beehaw.org 9 points 2 days ago (2 children)

When running cat this way, you are in "cooked mode". A ctrl-d does nothing on a non-empty line.

The shell usually runs in non-cokked, or raw, mode as well as nonblocking mode. Where it sees (nearly) every key you press as you press them. Which is why it " sees" the ctrl-d even when you are not on an empty line.

You can learn more here:

[–] cypherpunks@lemmy.ml 2 points 1 day ago

A ctrl-d does nothing on a non-empty line.

ctrl-d actually is flushing the buffer regardless of if the line is empty or not.

See my other comment for how you can observe it.

[–] tuna@discuss.tchncs.de 1 points 4 hours ago

Interesting, I have not heard of these terms before. Thanks for sharing!

I think this adds the bit of nuance that was bugging me: using something like ncurses or vim, presumably when you press a key like ctrl-z or ctrl-d it actually sends the character to the app. It would feel a bit silly if the terminal intercepted the ctrl-d, flushed some buffer, and the program had to reverse engineer whether you pressed ctrl-d or enter or something.

For raw mode, I assume the app asks the tty to please forward some characters to the app. Otherwise, in the default cooked mode, the tty intercepts those control characters to call certain functions. I suppose some REPLs may choose to emulate a cooked mode on top of raw mode, and so they have to handle the \x04 in the same way a tty would to keep it functioning like the user expects. I believe readline does something like this, which is why you had to use bash --noediting for ctrl-d to run the command. Good food for thought :)

I also have to say, naming it "cooked mode" is extremely funny as gen z. I love that

[–] skepller@lemmy.world 0 points 2 days ago* (last edited 2 days ago)

This!

It's merely a buffer flush, in case it's empty, the program handling the input can choose how to interpret, cat decides to do it as an EOF.

Reason why it also works as exit.

[–] ramius345@sh.itjust.works 9 points 2 days ago (1 children)

Ctrl+d terminates input on stdin to your currently running program or shell.

[–] tuna@discuss.tchncs.de 1 points 2 days ago (2 children)

not true. try this:

$ date<C-d>

bash did not terminate stdin, because when i press enter it still runs the command, and my shell continues to work as normal!

you can also try this:

$ bash --noediting
$ date<C-d><C-d>

and it will print the date.

so something else is happening here! thats what the link talks about in detail

[–] ramius345@sh.itjust.works 1 points 2 days ago (1 children)

For some reason my mobile client didn't make the article link immediately obvious. That's actually really interesting. Apparently I was under the same common misconception. So the shell in this case is choosing to continue after detecting the flush.

[–] tuna@discuss.tchncs.de 1 points 4 hours ago

Ohh I gotcha. Honestly no sweat, its kind of just a bit of fun trivia really :)

[–] mvirts@lemmy.world 5 points 2 days ago

Lol wrong again