windows和linux換行規則的區別

在計算機尚未出現以前,有一種叫作電傳打字機(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後面的字符被輸出到了行的開頭,覆蓋了原來的內容。

 

 

小結

    • windows下建立的文件換行符爲^M$,但最後一行結尾沒有換行符
    • linux下建立的文件,每一行都會以換行符$結束,包括最後一行
    • vim打開文件時,若是文件的全部換行符都是dos格式的^M$,那麼vim會自動以dos文件格式來顯示文本文件,不然會以默認的unix格式顯示文本,這是可能會在行的結尾出現^M的符號
    • wc -l是以$換行符來統計行數的,所以windows下建立的文件使用wc -l統計行數時會少一行
    • 一個windows下建立的文件,在linux下顯示正常,可是用某些文本處理命令,如sed處理後,文件的某些換行符可能會改變,形成顯示不正常
    • sed處理文件時,會把windows換行符中的^M看成文件內容,即sed只保留$做爲行末尾的換行符,所以可能會形成換行符不一致。
    • cat在不顯示特殊字符輸出文件內容時,會將^M看成回車命令處理,而$看成回車加換行。因此若是一個文件的換行符是混雜有linux和windows版本的,在vim下顯示時行尾爲多出一個^M, 而cat下會顯示正常(由於cat會把^M看成特殊字符處理)。但若是文件中間有^M這個特殊字符時,cat的顯示會出現一些問題。
相關文章
相關標籤/搜索