13

Perhaps there are already answers out there that indirectly answer my question, but I've read many of them and haven't yet found a satisfactory answer to this discrepancy.

The original meaning of carriage return comes from old teleprinters: it meant to move the print head to the left in the current line. If you kept writing in the current line, you would be overwriting what was already written. Nowadays, we can specify this behaviour with the text symbol \r, which is typed explicitly within a string. For example, in Python you can do print('hello\rgoodbye'), and in the terminal you can do echo $'hello\rgoodbye', and in both cases you will only see goodbye.

In contrast, a pseudo-carriage return can also be inserted interactively with the ASCII control character ^M (typed with Ctrl-M or with Enter). I call it pseudo-carriage return because even though it is widely called carriage return, surprisingly it doesn't insert \r, but rather it inserts \n, which is the symbol for a new line.

So interactively typing hello, then Ctrl-M, then goodbye, surprisingly doesn't achieve the equivalent of hello\rgoodbye, but rather the equivalent of hello\ngoodbye.

Isn't this very inconsistent? What is the rationale behind this?

mgarort
  • 455

1 Answers1

20

This is the result of the terminal’s input handling: by default, the terminal device driver (software in the kernel of your operating system to handle input from the terminal, not the terminal itself) converts CtrlM to CtrlJ. You can see this by running

od -t x1

and then entering both characters:

$ od -t x1
^M
^J
^D
0000000 0a 0a
0000002

(You won’t see ^M etc. on screen.)

Thus when you type CtrlM, whatever program is processing your input doesn’t see a carriage return, it sees a line feed instead.

This can be configured with stty icrnl. See Understanding Return, Enter, and stty icrlf for a similar question.

Stephen Kitt
  • 434,908
  • Hi, thanks a lot for your answer. If I understood correctly, there was some divergence such that many Unix programs and the C language started to use line feed ^J or \n, whereas terminals went their own way and started to interpret Enter as carriage return ^M or \r. At some point, Unix and C became very widespread, so terminals had to somehow revert back to be more compatible with Unix and C. The easiest way to do this was to add the layer of interpretation of stty icrnl, and convert ^M to ^J. Is this a roughly correct account of the historical development? – mgarort May 10 '21 at 13:17
  • 3
    I’m not sure when icrnl was added to termio or termios, but Unix always had a separation between its internal expectations and how terminals worked (inherited from Multics); I’m not sure things diverged as such, terminals were already varied when Unix was created. This related answer I wrote on Retro.SE goes into some of the history and provides pointers to more detailed explanations. – Stephen Kitt May 10 '21 at 15:52
  • This is an interesting answer, because it seems about the opposite of the way things work on Windows. There the Enter key is converted to \r\n, and the C runtime library will convert that back to \n if you open a file in "text" mode. – Mark Ransom May 11 '21 at 16:57