那天項目部署的時候,遇到一個很詭異的現象,一度懷疑本身職業生涯到此結束了,後面經排除發現,原來是
Linux
和Windows
下shell
腳本換行符的格式問題,致使腳本一直執行不了...(到此,標題所說的事故講完了...:)html
看起來很蠢的問題,溜了 :) ...但莎士比亞說過,解決一個問題最好的方式,就是下次不要再犯了。因此咱們刨根問底兒,完全搞清楚換行符在計算機系統中究竟是個啥玩意兒。linux
在計算機出現以前,有一種通訊設備叫電傳打字機(Teletype Mode),每秒輸出10個字符,平均每一個字符0.1秒,但有個問題,就是打完一行換行的時候,要消耗0.2秒,在這個時間段內,若是有新字符傳來,就將丟失,因此有人爲了解決這個問題,在每一行後面加兩個字符表示該行結束。shell
那這裏就涉及到兩個動做:vim
後面這個概念就被搬到了計算機系統上,But,有人的地方就有分歧,各大系統開始秀了。bash
Windows
系統裏,每行結尾是回車+換行(和上述提到的兩個動做一致),\r\n
;Unix
系統,每行結尾只有換行\n
;Mac
系統,每行結尾只有換行\n
;PS:老
MAC
系統用的\r
,如今的MAC
都是用的\n
,和Unix
一致了。運維
不一樣系統之間的換行規則的不一樣,致使不一樣系統下的文件交叉使用的時候,存在不一致,好比最多見的,Unix/Mac
系統下的文件在Windows
裏打開,全部文字會變成一行,緣由顯而易見。編輯器
二進制 | 十進制 | 十六進制 | 字符/縮寫 | 解釋 |
---|---|---|---|---|
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) | 不用切換 |
咱們一步步來實踐下上述說的,測試環境是
Windows
和Linux
。post
Windows
下新建個win.txt
文件,寫一句大白話。上面有聽講的同窗應該知道,這裏的換行符爲CRLF
。talk is cheap,
show me your code.
複製代碼
Linux
系統用vim
打開剛新建的文件這看起來不是挺正常的麼?和Windows
上顯示的同樣啊。注意這裏vim
查看文件的時候,會檢測換行符,若是全部的換行符都是CRLF
,那麼它會自動以dos
格式來顯示文本內容,最下面[dos]
裏也體現了這一點。測試
dos
(Disk Operating System 磁盤操做系統)和Windows
同樣採用的是CRLF
spa
cat -A
選項查看文本全部的字符能夠看到多了^M$
,^M
這是Linux
等系統下規定的特殊標記,佔一個字符大小,不是^
和M
的組合,只能用Ctrl+v,Ctrl+m
按出來;而$
不是換行符,能夠理解爲Linux
下用來表示文本結束EOF的符號。
cat -v
選項顯示出非打印字符sed -i '1s/^M//' win.txt
複製代碼
看到第一行的^M
不見了,第二行仍是保留。
結果展現vim
中多了^M
這個符號,左下角也沒了[dos]
的標識,這裏迴應了第二點提到的現象,表示vim
用Linux
來顯示文本內容。
到這一步爲止,咱們證明了Windows
和Linux
環境下不一樣換行規則帶來的差別。
看到社區裏的小夥伴作了這個嘗試,便參考着作了下,能夠直觀體現什麼是「回車」。
cat -A
查看全部字符sed -i '1s/.*/& ypm/g' win.txt
在第一行末尾加上ypm
.*
匹配整行的時候,不包括換行符^M
,因此ypm
加在了第一行的末尾cat
正常查看文本的時候,發現一件奇怪的事情,ypm
覆蓋了talk
,怎麼解釋?咱們要知道
cat
普通模式下輸出文本內容,會將^M
理解爲回車。
這就能夠解釋了,遇到回車符,就像打印探頭從右回到了左,ypm
這裏的四個字符,恰好覆蓋了talk
四個字符。這就直觀解釋了什麼是回車。
談到如何規避這個差別,其實不一樣方向上有不一樣方法,好比針對^M
、強制轉換文本格式,但我的以爲,能解決其根本問題的,仍是在不一樣系統間,代碼編輯的時候,注意到這個格式問題,各大IDE都有本身的解決方案。
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
複製代碼
dos2unix win.txt
複製代碼
\r
:CR(carriage return)\n
:LF(line feed)Windows
系統遵循最原始的規則,即必須知足回車符+換行符,缺乏或者順序調換都不可,即\r\n
Unix
系統中遇到換行符\n
就會進行回車+換行的操做,而回車符\r
會做爲特殊字符^M
顯示沒想到這麼簡單的問題,扯了這麼多,其實不少小夥伴也都遇到過這個問題,社區裏也常常有由於換行符致使的「血案」,但願沒有所以釀成以前那個程序猿小哥手誤致使的幾千萬的損失。在運維、DB等領域,這些「小問題」可能會被放大,所以仍是須要引發重視,雖然有不少規避手段,但在代碼編寫的初期,就應該養成習慣關注到這一點,排查問題的時候這一樣是一個方向。
PS: 可能會有不嚴謹的地方,也歡迎你們討論,輕噴...