Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo

agnos.is Forums

  1. Home
  2. Linux
  3. Linux Terminal: CTRL+D is like pressing ENTER

Linux Terminal: CTRL+D is like pressing ENTER

Scheduled Pinned Locked Moved Linux
linux
20 Posts 11 Posters 0 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T [email protected]
    $ 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.

    S This user is from outside of this forum
    S This user is from outside of this forum
    [email protected]
    wrote on last edited by
    #11

    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.

    1 Reply Last reply
    0
    • T [email protected]

      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 🙂

      M This user is from outside of this forum
      M This user is from outside of this forum
      [email protected]
      wrote on last edited by
      #12

      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.

      If you think ^D is like Enter, start a shell and without running a command press ^D.

      ferk@lemmy.mlF cypherpunks@lemmy.mlC 2 Replies Last reply
      0
      • M [email protected]

        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.

        If you think ^D is like Enter, start a shell and without running a command press ^D.

        ferk@lemmy.mlF This user is from outside of this forum
        ferk@lemmy.mlF This user is from outside of this forum
        [email protected]
        wrote on last edited by
        #13

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

        1 Reply Last reply
        0
        • davel@lemmy.mlD [email protected]

          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.

          ferk@lemmy.mlF This user is from outside of this forum
          ferk@lemmy.mlF This user is from outside of this forum
          [email protected]
          wrote on last edited by
          #14

          Yes, ^M it's the "Carriage Return" (CR) character, /r, the 13th control character in ASCII.

          That's why if you open in Linux a Windows file in vim with Windows style EOL, you always see a strange ^M symbol at the end of each line.

          1 Reply Last reply
          0
          • T [email protected]

            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 🙂

            M This user is from outside of this forum
            M This user is from outside of this forum
            [email protected]
            wrote on last edited by
            #15

            Lol wrong again

            1 Reply Last reply
            0
            • M [email protected]

              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.

              If you think ^D is like Enter, start a shell and without running a command press ^D.

              cypherpunks@lemmy.mlC This user is from outside of this forum
              cypherpunks@lemmy.mlC This user is from outside of this forum
              [email protected]
              wrote on last edited by
              #16

              Note: for novices reading along at home, 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.

              Nope, Chuck Testa: there is no EOF character. ^*^

              "D" being the fourth letter of the alphabet, sends ASCII character 4, which (as you can see in man ascii) is called EOT or "end of transmission".

              $ 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)
              

              What this means is that the character specified after eof (by default ^D, aka EOT) is configured to be intercepted (by the tty driver) and, instead of that character being sent to the process reading standard input, the kernel will "send an end of file (terminate the input)".

              ::: spoiler (*)
              One could also say there is an EOF character, but what it is can be configured on a per-tty basis.

              By default the EOF character is EOT, a control character, but it could 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.
              :::

              But "send an end of file" does not mean sending any 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. (cat will echo those characters, 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.

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

              On success, the number of bytes read is returned (zero indicates end of file)

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

              $ 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 ^V and ^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.

              ::: spoiler (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?
              

              :::

              Anyway, hopefully this all convinces you that EOF is not a character 🙂

              M 1 Reply Last reply
              0
              • ? Guest

                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:

                • https://jvns.ca/blog/2024/11/26/terminal-rules/#rule-3-repls-should-quit-when-you-press-ctrl-d-on-an-empty-line. (And more generally, from her various blog posts on the matter)
                • https://www.gnu.org/software/mit-scheme/documentation/stable/mit-scheme-ref/Terminal-Mode.html
                cypherpunks@lemmy.mlC This user is from outside of this forum
                cypherpunks@lemmy.mlC This user is from outside of this forum
                [email protected]
                wrote on last edited by
                #17

                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.

                1 Reply Last reply
                0
                • cypherpunks@lemmy.mlC [email protected]

                  Note: for novices reading along at home, 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.

                  Nope, Chuck Testa: there is no EOF character. ^*^

                  "D" being the fourth letter of the alphabet, sends ASCII character 4, which (as you can see in man ascii) is called EOT or "end of transmission".

                  $ 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)
                  

                  What this means is that the character specified after eof (by default ^D, aka EOT) is configured to be intercepted (by the tty driver) and, instead of that character being sent to the process reading standard input, the kernel will "send an end of file (terminate the input)".

                  ::: spoiler (*)
                  One could also say there is an EOF character, but what it is can be configured on a per-tty basis.

                  By default the EOF character is EOT, a control character, but it could 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.
                  :::

                  But "send an end of file" does not mean sending any 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. (cat will echo those characters, 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.

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

                  On success, the number of bytes read is returned (zero indicates end of file)

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

                  $ 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 ^V and ^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.

                  ::: spoiler (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?
                  

                  :::

                  Anyway, hopefully this all convinces you that EOF is not a character 🙂

                  M This user is from outside of this forum
                  M This user is from outside of this forum
                  [email protected]
                  wrote on last edited by
                  #18

                  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.

                  1 Reply Last reply
                  0
                  • ? Guest

                    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:

                    • https://jvns.ca/blog/2024/11/26/terminal-rules/#rule-3-repls-should-quit-when-you-press-ctrl-d-on-an-empty-line. (And more generally, from her various blog posts on the matter)
                    • https://www.gnu.org/software/mit-scheme/documentation/stable/mit-scheme-ref/Terminal-Mode.html
                    T This user is from outside of this forum
                    T This user is from outside of this forum
                    [email protected]
                    wrote on last edited by
                    #19

                    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

                    1 Reply Last reply
                    0
                    • R [email protected]

                      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.

                      T This user is from outside of this forum
                      T This user is from outside of this forum
                      [email protected]
                      wrote on last edited by
                      #20

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

                      1 Reply Last reply
                      0
                      • System shared this topic on
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups