在计算机尚未出现以前,有一种叫作电传打字机(Teletype Model 33)的玩意,每秒钟能够打10个字符。可是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好能够打两个字符。要是在这0.2秒里面,又有新的字符传过来,那么这个字符将丢失。html
因而,研制人员想了个办法解决这个问题,就是在每行后面加两个表示结束的字符。一个叫作"回车"(Carriage Return),告诉打字机把打印头定位在左边界;另外一个叫作"换行"(Linefeed),告诉打字机把纸向下移一行。linux
这就是"换行"和"回车"的来历,从它们的英语名字上也能够看出一二。正则表达式
后来,计算机发明了,这两个概念也就被般到了计算机上。那时,存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就能够。因而,就出现了分歧。vim
Unix系统里,每行结尾只有"<换行>",即"\n";Windows系统里面,每行结尾是"<回车><换行>",即"\r\n";Mac系统里,每行结尾是"<回车>"。一个直接后果是,Unix/Mac系统下的文件在Windows里打开的话,全部文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。windows
(以上内容转载自阮一峰blog)编辑器
所以在linux下建立的文本文件在windows中会连成一行,由于windows认为没有换行符(CRLF)。
在windows下建立的文本文件在linux中可能会出现每一行后面多了一个^M,这个^M要用ctrl + v ctrl + m打出,表明的意思就是CR(Carriage Return).post
说到这里有人也许会问,为何我在windows下建立的文本文件,在linux中显示正常呢?spa
例如,我在windows下建立一个文本文件a.txt,放到个人linux中,用vim打开命令行
能够看到显示结果正常,行的结尾并无^M符号。这是由于vim在打开文件时,会自动检测换行符,若是文本的全部换行符都是^M$(CRLF, 即windows的换行标记),那么vim会自动以dos格式显示文本内容,忽略掉每一行结尾的^M$,所以文本显示是正常的。3d
注意上面我图片的两个箭头指示的vim编辑器最下方的两个标志[noeol]和[dos],先来解释第二个标志"[dos]",这表示vim识别到文本的每一行都是^M$的换行符,所以vim自动以dos文本格式来显示文件。因此咱们看到文本显示是正常的。
那么为何有的时候windows下建立或编辑的文件在linux下会出现^M呢,vim不是能自动识别吗?这是由于,vim会检查文本的每一行换行符,只要有一行的换行符不是windows格式,那么vim就会以unix文件格式来显示文件,这时换行符为$, 所以咱们会看到文本的行后面多了一个^M符号。
这里我用cat -A显示文件的特殊符号:
文件一共四行,能够看换行符都是^M$(箭头所指),所以vim会用[dos]文件格式来显示这个文本。
这里还能够发现文件的最后一行没有换行符,这就是第一张图vim中的[noeol]标志的由来 ,由于在windows下处理的文本,最后一行是不会加上换行符的,而linux下建立的文本的规则是每一行都有换行符,包括最后一行。所以vim会提示no end-of-line, 告诉咱们这个文件包含没有换行符结束的行。
用wc -l统计这个文件的行数:
结果是3行,少了一行,缘由是文件的最后一行没有换行符。
我在linux下用vim编辑一个新文件,内容和刚刚的a.txt同样,用cat -A查看:
能够看到linux下建立的文本,每一行都是有换行符的,包括最后一行,用wc -l统计行数:
这时统计结果正确。
再用sed替换windows下建立的a.txt, 将其中一行的换行符^M$中的^M去掉,变成linux的换行符$
这里我把文件的第二行的换行符替换成了linux格式的$,注意sed命令中的^M
在命令行中不是直接输入,而是 ctrl+v和ctrl+m. 再用vim打开这个文件:
因为第二行的换行符不是^M$格式,vim不会以dos文件格式来显示文件按,能够发现vim下方没有[dos]的提示了,代表vim以unix文件格式来显示这个文件,所以一些行的后面会多了一个^M标志。
补充:sed对windows换行符的处理
经过上面能够知道vim对于一个所有使用windows格式换行符的文本文件会以[dos]模式来显示这个文本,自动忽略行尾的^M.
博主在使用sed命令处理一些文件时,会出现一个原本显示正常的文件,被sed处理以后,再打开文件时发现再次出现讨厌的^M. 那么sed是如何处理windows换行符的文本呢?
先在windows下建立一个文本文件,传至个人linux中。用cat -A 显示特殊字符:
这里看到最后一行没有换行符,其余行的换行符为^M$, 使用sed处理这个文本文件,向第二行添加一些内容,再用cat -A查看:
这里我用.*匹配第二行的全部内容,&表示匹配到的全部内容,在&后面我加上了一些内容,用cat -A查看发现,sed在处理替换时,若是匹配到整个行,那么匹配的内容是除了换行符$(Linux 换行符)外的全部内容,即便这个文本的换行符是^M$(windows 换行符).
所以第二行的文本被sed处理后,^M被个人正则表达式.*看成文本内容而匹配到了,而$不会被匹配,永远在行的末尾充当换行符,这样一来^M和$就被拆散了。所以这一行的换行符在处理后成为了linux格式的换行符$. 用vim打开的效果以下:
由于文件的换行符是linux和windows混杂的,vim以unix文件格式显示这个文件,文件的^M被显示出来,而且第二行的^M被sed匹配到,于是不在行尾。vim下方的[noeol]缘由是最后一行在windows下没有换行符,所以也没有^M.
得出结论:sed会把文件中的^M看成文件内容来处理,所以若是用sed处理windows下建立的文本文件,颇有可能在处理以后显示时出现讨厌的^M. 关于其余的文本处理器如何处理windows的换行符,还有待进一步研究。
在补充:用cat显示文本时windows与linux换行符的处理
仍是上面的文件,在使用sed命令替换以后用cat -A查看文件内容:
不显示特殊字符,使用cat查看文件,发现显示以下:
发现第二行的内容和预想的不同,我明明是在文件末尾加上的" hello"这个字符串,为何跑到文件开头了呢,并且还覆盖了原来的字符。
第二行原来的内容是这样的(红色为特殊字符):
My name is Liao^M hello$
前面说过,^M这个特殊字符(注意这是一个特殊字符而不是两个)所表明意义是回车(Carrige Return). cat在显示第二行内容的时候从第二行的开头开始读取字符并输出到屏幕上,当读取到^M这个特殊字符时,将这个特殊字符的意义理解为最原始回车,打字机时代,回车表示机头回到一行的开头(注意只是回到当前行开头,换行的意义才是移动到下一行),所以cat会回到行的开头开始输出字符到屏幕,后面的字符被显示到了这一行开头,这样就会把本来这一行开头的字符覆了。当打印到这一行的末尾时,读取到了$linux换行符,而后换下一行行头开始读取和输出字符。这样就形成了第二行显示时的奇怪现象。
结论:cat在普通输出内容的模式下,会将^M字符理解为回车,即回到当前行的开头,$字符理解为回车加换行,即到下一行行头开始输出内容。这样若是一个文本的行当中包含一个^M字符时,cat在显示这个文件时会出现意想不到的状况。
例如,我手动建立一个一行的文本,在文本中加入一个回车符^M:
而后用cat显示这个文件:
能够发现cat在读取到^M以后回到行的开头开始输出,所以^M后面的字符被输出到了行的开头,覆盖了原来的内容。
小结: