眾所周知,不同的作業系統中,對文字中換行的表示是不同的,在 windows 中用\r\n
表示,在 linux 中用\n
表示,而在 mac os 中用\r
表示。對於像筆者這種以 windows 作為開發環境,linux 作為執行環境的程式設計師來說,經常會不可避免地碰到由換行符不一致而引起到奇怪問題,下面就回溯一下我曾遇到並解決的兩個相關的問題,希望能給讀者來一點啟發。
這是同事遇到的問題,其當時在開發乙個 shell 指令碼,需要乙個從檔案中查詢關鍵字的功能,比如檔案名叫data.txt
,要查詢到關鍵字是warn
,很容易寫出這樣的命令:
grep warn data.txt
假如檔案的內容是:
warn: wrong
info: good
warn: not good
那麼該命令因該返回兩行:
warn: wrong
warn: not good
到這裡,一切都正常,但是這位同事不滿足於只將結果列印到標準輸出,而是要用乙個變數儲存,以便後續的操作,於是寫下了這樣兩行指令碼:
result=$(
grep
warn data.txt)
echo $result
這時奇怪的事發生了,執行這個指令碼得到的結果是:
_warn: not good # 注意 'warn' 前面有乙個空格,為了醒目,用 '_' 表示
相信讀者已經猜到,導致這個現象的原因,就是\r
字元。下面解釋一下原因。
這個檔案的出處現已無從考證,但其中每行都是以\r\n
結束, 推測應該是從 windows 平台拷貝過來的。但是在 linux 中,只有\n
被作為換行符,其前面的\r
字元將被視為普通的文字內容處理,所以grep
命令返回到結果應該為:
warn: wrong\r
warn: not good\r
在向螢幕列印這段內容時,\r
字元會被轉義為回車符,其作用是將游標即下乙個字元的輸出位置移動到本行行首(windows 上的\r\n
可以理解為先將輸出位置移動到行首,再用\n
移動到下一行),但由於\r
後面再無其它字元,所以對使用者來說,僅游標位置的移動是感知不到的。
但在指令碼中,情況有了些許的變化——grep
的結果不直接列印,而是先賦值給變數,再列印變數。區別在於指令碼中會將result
中的內容按行分割,再依次傳給echo
,實際執行的命令為:
echo warn: wrong\r warn: not good\r
上面已經說過,\r
字元會使游標回到行首,所以第乙個\r
字元前的內容會被後面的內容覆蓋,這便是問題所在。
其實只要將輸出命令寫成:
echo
"$result"
而不是
echo
$result
就不會有這個問題,因為雙引號中的內容會被當作純粹的字串處理,不做轉義,實際的命令為:
echo
"warn: wrong\r
warn: not good\r"
內容分為兩行列印,和直接用grep
輸出的結果一樣。
這次到問題出現在另一同事的指令碼中,其內容只有兩行編譯命令,被打在乙個 rar 包中發給我。兩行命令的內容都查不多,但命令的內容無關緊要,假設為:
g++
-wall source.cpp -i
...-l
...-o source -l***
其中的 *** 是乙個本專案的動態庫。我直接在本地執行該指令碼,但鏈結失敗,報 『***』 庫找不到。
第一反應當然是庫所在的目錄沒有被加到動態庫的搜尋路徑中,但檢查了一遍發現不是。又懷疑命令寫的有問題、動態庫檔案沒有讀許可權、檔名寫錯,但都驗證通過了。折磨了有半個小時,突然靈光一現,用dos2unix
命令轉換了一下編譯指令碼,隨即編譯通過。
原因很簡單,這個指令碼中每一行的末尾都有乙個\r
,恰好跟在 『***』 後面,變成了 『***\r』,鏈結時實際查詢的是 『***\r』 檔案,當然找不到了。但由於列印到螢幕上的內容是一樣到,所以很難發現。
兩次請求與三次握手
在使用 時。第一次訪問伺服器時,顯示request建立銷毀了三次,session建立銷毀了三次,這是由於網路傳輸是基與http協議的,而http協議在在第一次訪問伺服器時進行的是三次握手。所以顯示三次。在於伺服器建立鏈結後,關閉瀏覽器,重新開啟頁面會產生兩次request的建立與銷毀,一次sessi...
一次fork與兩次fork的區別
在講一次fork和兩次fork之前,有必要先來簡單講解一下wait的作用 1 阻塞當前程序 2 獲得子程序退出的相關資訊 殭屍程序 子程序不返回,父程序後邊的內容就沒法執行。注 wait函式只能在有子程序的父程序中呼叫。我們使用fork 函式建立乙個子程序出來往往是為了父子程序能夠同時執行兩段 如果...
listview 重新整理兩次的問題
遇到個奇怪的現象,listview每次都重新整理兩次,在網上查詢了好久,無果,後來看見一片部落格中提到 的getview會重複執行多次,這次因為布局比較複雜,所以在測試的時候去斷點跟蹤,發現同一條資料不斷的重複執行 listview是根據布局來確定當錢重新整理的item並確定是否重新整理完畢,我按照...