如果你在Linux環境底下用vi開啟DOS/Windows檔案的話,很有可能你在每行的結尾會看到一個『^M』的符號。若只是一般文字檔的話,只會造成閱讀的困擾,倒還沒有其他問題。但是如果是shell script 的話,這可會造成執行錯誤。對於第一次遇到這個問題的人,恐怕是一頭霧水。

為了瞭解這個問題,首先我們來看看Linux的每行結尾和DOS/Windows有什麼不一樣。我們做了兩個檔案:Linux 格式的linux_file和DOS格式的dos_file,分別用hexdump來看看檔案結尾。

首先是Linux的檔案,從紅色部分的標示可以看出來檔案結尾是十六進位的0x0a:

$ hexdump -C linux_file
00000000  4c 69 6e 75 78 2d 66 6f  72 6d 61 74 20 66 69 6c  |Linux-format fil|
00000010  65 2e 0a 45 6e 64 65 64  20 77 69 74 68 20 30 61  |e..Ended with 0a|
00000020  2e 0a                                             |..|
00000022
$

 

再來是DOS的檔案,從紅色部分的標示可以看出來檔案結尾是十六進位的0x0d 0x0a:

$ hexdump -C dos_file
00000000  44 4f 53 2d 66 6f 72 6d  61 74 20 66 69 6c 65 2e  |DOS-format file.|
00000010  0d 0a 45 6e 64 65 64 20  77 69 74 68 20 30 64 20  |..Ended with 0d |
00000020  30 61 2e 0d 0a                                    |0a...|
00000025
$

 

因為DOS的檔案格式比Linux的格式多了個0x0d,所以會在vi裡面多了一個^M的符號(M是第13個字母,而0x0d就是十進位的13).

0x0d 和 0x0a 這兩個十六進位值除了用控制字元來表示以外,通常也用跳脫字元(Escape character)的 \n 和 \r 來表示。  整理之後,可以得到以下這個表格: 

行尾(end of line) 表示法

檔案格式

十六進位

控制字元 (Control character)

跳脫字元 (Escape character)

ASCII 名稱

Linux

0x0a

^J

\n

LF

DOS/Windows

0x0d 0x0a

^M ^J

\r \n

CR LF

 

知道了Linux與DOS檔案格式的差別之後,要處理這個問題也就呼之欲出了。在Linux的shell 命令裡,有兩個簡單的方法可以消除這個^M。

第一種方法,是利用sed的替換命令,將\r換成空字元:

sed  "s/\r//" dos_file  > dos_file_linux

 

第二種方法,是利用tr的刪除命令,將\r刪除:

tr -d "\r" < dos_file  > dos_file_linux

 

任何一種方法做完之後,DOS的行尾已經轉換成Linux行尾:

$ hexdump -C dos_file_linux
00000000  44 4f 53 2d 66 6f 72 6d  61 74 20 66 69 6c 65 2e  |DOS-format file.|
00000010  0a 45 6e 64 65 64 20 77  69 74 68 20 30 64 20 30  |.Ended with 0d 0|
00000020  61 2e 0a                                          |a..|
00000023
$

 

(2012/10/16 Update) 在某些系統上可能會有dos2unix這個方便的小程式,以下的例子把 DOS 格式的 a.txt轉換成Linux格式的b.txt

dos2unix a.txt b.txt

 

延伸閱讀

Wiki: Newline

Wiki: Control Character

創作者介紹

真實旅程

dragonspring 發表在 痞客邦 PIXNET 留言(0) 人氣()