記一次換行符引起的事故

那天項目部署的時候,遇到一個很詭異的現象,一度懷疑本身職業生涯到此結束了,後面經排除發現,原來是LinuxWindowsshell腳本換行符的格式問題,致使腳本一直執行不了...(到此,標題所說的事故講完了...:)html

看起來很蠢的問題,溜了 :) ...但莎士比亞說過,解決一個問題最好的方式,就是下次不要再犯了。因此咱們刨根問底兒,完全搞清楚換行符在計算機系統中究竟是個啥玩意兒。linux

歷史來源

在計算機出現以前,有一種通訊設備叫電傳打字機(Teletype Mode),每秒輸出10個字符,平均每一個字符0.1秒,但有個問題,就是打完一行換行的時候,要消耗0.2秒,在這個時間段內,若是有新字符傳來,就將丟失,因此有人爲了解決這個問題,在每一行後面加兩個字符表示該行結束。shell

那這裏就涉及到兩個動做:vim

  • 將打印探頭(就如上圖的那個刻度上的頭子)從右邊拉回到左邊,這就是回車(carriage return)
  • 拉回到左邊還不夠,還要將探頭換行(相對應的就是將紙往上吐一行的距離),這就是換行(line feed)

後面這個概念就被搬到了計算機系統上,But,有人的地方就有分歧,各大系統開始秀了。bash

  • Windows系統裏,每行結尾是回車+換行(和上述提到的兩個動做一致),\r\n;
  • Unix系統,每行結尾只有換行\n;
  • Mac系統,每行結尾只有換行\n;

PS:老MAC系統用的\r,如今的MAC都是用的\n,和Unix一致了。運維

不一樣系統之間的換行規則的不一樣,致使不一樣系統下的文件交叉使用的時候,存在不一致,好比最多見的,Unix/Mac系統下的文件在Windows裏打開,全部文字會變成一行,緣由顯而易見。編輯器

ASCII碼

二進制 十進制 十六進制 字符/縮寫 解釋
00001001 9 09 HT (Horizontal Tab) 水平製表符
00001010 10 0A LF/NL(Line Feed/New Line) 換行鍵
00001011 11 0B VT (Vertical Tab) 垂直製表符
00001100 12 0C FF/NP (Form Feed/New Page) 換頁鍵
00001101 13 0D CR (Carriage Return) 回車鍵
00001110 14 0E SO (Shift Out) 不用切換

實踐見真章

咱們一步步來實踐下上述說的,測試環境是WindowsLinuxpost

  1. Windows下新建個win.txt文件,寫一句大白話。上面有聽講的同窗應該知道,這裏的換行符爲CRLF
talk is cheap,
show me your code.
複製代碼
  1. Linux系統用vim打開剛新建的文件

這看起來不是挺正常的麼?和Windows上顯示的同樣啊。注意這裏vim查看文件的時候,會檢測換行符,若是全部的換行符都是CRLF,那麼它會自動以dos格式來顯示文本內容,最下面[dos]裏也體現了這一點。測試

dos(Disk Operating System 磁盤操做系統)和Windows同樣採用的是CRLFspa

  1. 使用cat -A選項查看文本全部的字符

能夠看到多了^M$^M這是Linux等系統下規定的特殊標記,佔一個字符大小,不是^M的組合,只能用Ctrl+v,Ctrl+m按出來;而$不是換行符,能夠理解爲Linux下用來表示文本結束EOF的符號。

  1. 使用cat -v選項顯示出非打印字符

  1. 把第一行的回車符去掉再看看
sed -i '1s/^M//' win.txt
複製代碼

看到第一行的^M不見了,第二行仍是保留。

  1. 再重複第一步看看變化

結果展現vim中多了^M這個符號,左下角也沒了[dos]的標識,這裏迴應了第二點提到的現象,表示vimLinux來顯示文本內容。

到這一步爲止,咱們證明了WindowsLinux環境下不一樣換行規則帶來的差別。

驗證下回車符的真實存在

看到社區裏的小夥伴作了這個嘗試,便參考着作了下,能夠直觀體現什麼是「回車」。

  1. 還原上述的例子,cat -A查看全部字符
  2. sed -i '1s/.*/& ypm/g' win.txt在第一行末尾加上ypm
  3. 再次查看,咱們發現上面執行的命令用.*匹配整行的時候,不包括換行符^M,因此ypm加在了第一行的末尾
  4. cat正常查看文本的時候,發現一件奇怪的事情,ypm覆蓋了talk,怎麼解釋?

咱們要知道cat普通模式下輸出文本內容,會將^M理解爲回車。

這就能夠解釋了,遇到回車符,就像打印探頭從右回到了左,ypm這裏的四個字符,恰好覆蓋了talk四個字符。這就直觀解釋了什麼是回車。

如何規避

談到如何規避這個差別,其實不一樣方向上有不一樣方法,好比針對^M、強制轉換文本格式,但我的以爲,能解決其根本問題的,仍是在不一樣系統間,代碼編輯的時候,注意到這個格式問題,各大IDE都有本身的解決方案。

  1. 去除回車符號
cat -v win.txt | tr -d '^M'  > linux.txt
或者
cat win.txt |tr -d '\015' > linux.txt
或者
cat win.txt |tr -d '\r' > linux.txt
複製代碼
vim 編輯器中輸入
:%s/^M//g
或者
:set fileformat=unix
複製代碼
  1. 終端命令轉換
dos2unix win.txt
複製代碼

總結

  • 回車符 \r:CR(carriage return)
  • 換行符 \n:LF(line feed)
  • Windows系統遵循最原始的規則,即必須知足回車符+換行符,缺乏或者順序調換都不可,即\r\n
  • Unix系統中遇到換行符\n就會進行回車+換行的操做,而回車符\r會做爲特殊字符^M顯示

沒想到這麼簡單的問題,扯了這麼多,其實不少小夥伴也都遇到過這個問題,社區裏也常常有由於換行符致使的「血案」,但願沒有所以釀成以前那個程序猿小哥手誤致使的幾千萬的損失。在運維、DB等領域,這些「小問題」可能會被放大,所以仍是須要引發重視,雖然有不少規避手段,但在代碼編寫的初期,就應該養成習慣關注到這一點,排查問題的時候這一樣是一個方向。

PS: 可能會有不嚴謹的地方,也歡迎你們討論,輕噴...

參考

www.ruanyifeng.com/blog/2006/0…

www.cnblogs.com/linuxnote/p…

blog.csdn.net/zhangguangy…

相關文章
相關標籤/搜索