下图是上古时期的机械打字机,每输入一个字符,滚筒会左移一小截(一个字符的宽度 + 字符间距,好在那时候打字机都是等宽字体)。当滚筒移动到最左侧,即纸张右侧已经和敲针对齐时(也就是打完一行字),会有响铃提示已经抵达行末。这时拉动左侧墨带盒上边的金属手柄(换行手柄),然后滚筒会被推到最右边,打字头对准了行首,这就是 CR(carriage return, 回车)。继续用力,换行手柄大约会被扳动 30 度左右,纸会被上卷一行(行高,line height),这就是 LF(line feed, 换行)。

typewriter

如果只换行不回车,那么第一行敲满以后,敲针始终在纸张右侧,无法继续输入;只回车不换行,所有的内容都敲到同一行里了。

可以看下这两个视频:Olympia SM9 Typewriter DemoHow to Use a Typewriter

在最早的 ASCII 标准(1963-1968)中,有两套标准,一套是 ISO 出的认为 CRLFLF 都是标准的;然而另一套是 ASA 出的只认为 CRLF 是符合标准的。

所以 MS-DOS(1981)设计的时候是采用了在两种方法中都符合标准的 CRLF,一方面是满足了两个标准,另一方面是兼容了当时大量采用 CRLF 的计算机。而 Unix 的前身 Multics 的设计者认为在每行的结尾加两个字符用于换行,实在是极大的浪费(那时的存储设备非常昂贵)。所以 Multics 里面用一个驱动程序自动将 LF 转换成 CR-LF,所以他们用了单一的 LF

很明显,CRLF 才是正统,*nix 是异端。关于 CRLF 的表示如下:

CR(carriage return, 回车)用 \r (return)表示,对应的 ASCII 码为 0x0D

LF(line feed, 换行)用 \n (newline)表示,对应的 ASCII 码为 0x0A

所以现在各操作系统对换行的表示方式如下:

LF:在 Unix 或 Unix 相容系统(GNU/Linux,AIX,Xenix,Mac OS X,…)、BeOS、Amiga、RISC OS
CR+LF:MS-DOS、微软视窗操作系统(Microsoft Windows)、大部分非 Unix 的系统
CR:Apple II 家族,Mac OS 至版本 9

假设有这样一段文本:

aaa
bbb
ccc

如果这段文本是在 Windows 下编辑的,当它移植到 Linux 下,用 vim 打开会显示:

aaa^M
bbb^M
ccc^M

如果你的 vim 正常显示(可能是vim的版本比较高),可以 cat -A 一下,会显示:

aaa^M$
aaa^M$
aaa^M$

这里的 ^M 不是 ^ 符号加 M,而是一个组合字符,代表 CR

目前大多数文本编辑器都能够进行不同的换行符之间的转换(Windows 系统的记事本不行……)。如果是在 linux 下可使用如下命令进行转换:

$dos2unix file_name
$unix2dos file\_name

当然,你的系统可能没有这个命令,那么你可以用 vi 或者 vim 打开,然后在命令模式下输入:

%s/^M$//g #这里的^M是Ctrl+v+m`

如果你的 vi 或者 vim 正常显示了,那么上面这个办法也是行不通的,这时可以使用 sed,命令如下:

$sed -i 's/^M//g' filename    #这里的 ^M 仍然是 Ctrl+v+m
$sed -i 's/\r//g' filename    #与上一个命令相同

或者使用 tr 命令:

$tr -d '\r' < inputfile > outputfile #CRLF 转 LF
$tr '\r' '\n' < inputfile > outputfile #CR 转 LF

如果是在 Mac OS 9 或者 Linux 系统下编辑的,当它移植到 Windows 下,用记事本打开会显示:

aaabbbccc

但是不妨写这样一段C语言程序:

printf("aaa\n");
printf("bbb\n");
printf("ccc\n");

在控制台下输出为:

aaa
bbb
ccc

即便是将输出定向到文件用记事本打开,显示依然如上所示。这就有些坑了,再来这样一段程序:

char c;
c = getchar();
printf("%d\n", c);

输入回车,输出 10,说好的 Windows 下按一下 Enter 键输入两个字符,为什么只剩下一个了呢?再比如这样一段程序:

printf("aaa\n");
printf("bbb\r\n");
printf("ccc\r\r\n");

输出都是一样的换行。编译器做了什么,Windows 系统做了什么,我无从知晓,既然已经理不清其中的原因,那最好的办法就是避开这个陷阱。如果你对此事的兴趣非常强烈,不妨看下这个:在 Windows 下键入 Enter 键,是在键盘缓冲区中存入 ‘\n’ 还是 ‘\r’’\n’ 两个?

参考

文档信息

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。
本文链接:www.snovey.com/2016/06/endofline.html