DOS,UNIX中的回車換行區別

miguelmin發表於2009-02-06

這幾天寫了個多執行緒的資料抽取perl指令碼,速度很快,可達到1G/m以上。可是今天做fastload載入時,被破了瓢冷水:
抽過來的所有的檔案都無法正常的載入,表現的形式是我抽取的資料始終要比BOSS送過來的資料大那麼一點點,但記錄
條數沒有異常。於是我開始了艱難的查錯之旅:

[@more@]1.用UE檢視資料檔案,無明顯異常:
2.用cygwin檢視各條記錄的長度,輸出長度不對的行:
awk '{ if ( length($0) !=行位元組數) {print $0;print NR} }' xxx.dat
結果令我失望,所有行的長度均正常;
3.編寫一perl指令碼,比較我抽取的資料檔案和正確檔案的差異:
#!/user/bin/perl

use strict;
use File::Basename;
use POSIX qw(strftime);

open(IN, "E:ETLDATAprocessQ01_CUST_PERSON_INFO_T_20090203.dat") or die "open error: $!";
my @x = ;
close (IN);
open(IN, "E:ETLDATAprocessQ01_CUST_PERSON_INFO_T_20090203_1.dat") or die "open error: $!";
my @y = ;
close (IN);

chomp(@y);
my $p = join('|', map{quotemeta} @y);
#print (grep /$p/, @x);
print (grep ! /$p/, @x);
五分鐘後,執行完畢,結果令人沮喪,輸出日誌大小為0;
4.我開始懷疑是不可見字元引起的異常,可是這個怎麼查呢?
5.新的一天開始了,有高手過來,機會難得,開問。高手就是高手,聽了我的描述,他決定用UE檢視檔案的十六進位制編碼,
用UE開啟,彈出視窗:"轉換成DOS模式",點“是”,比較兩檔案的十六進位制編碼,發現完全一樣!
怎麼辦呢?先看看大小差異有沒有什麼規律:
一行資料可見字元的長度為388*25538=9908744
正常:9934282 = 9908744 + 25538
異常:9959820 = 9934282 + 25538
也就是說正常情況下不可見字元數為每行1個,而我抽取的為每行2個
再用UE開啟,彈出視窗:"轉換成DOS模式",點“是”,比較兩檔案的十六進位制編碼,重點關注不可見的回車換行符,發現還是完全一樣!怎麼回事呢?突然想起BOSS的資料庫環境為UNIX,是不是編碼不一樣呢?找到UE選單中“DOS到UNIX”轉換,轉換格式,儲存。發現大小變為正確值,fastload,成功。突然明白,檢視十六進位制編碼完全一樣的罪魁禍首在於慣性的點選UE彈出的"轉換成DOS模式"。驗證一下,點選彈出視窗的“否”,果然發現區別,抽取資料的回車換行的編碼為“0A0D”,正確資料為“0D”。

結論:dos與unix在檔案中換行字元的表現機置存在差異:
dos格式下,切換一行是二個字元的,由回車(od),換行(oa),檔案尾部直接EOF(檔案結束標誌)
而unix下,切換一行,使用的是單換行符(oa),檔案最後一行也會增加該字元,然後才是eof

驗證如下:
windos下建一個檔案,1.txt,輸入:

afew
aef(到此打住)

使用ultraedit的十六進位制檢視,或者上傳到unix機,使用:"xxd 檔名"以十六進位制檢視檔案,結果如下:

0000000: 6166 6577 0d0a 6165 66 afew..aef

增加了Od,Oa二個字元

而在unix下,簡單建立一個同樣的檔案:"vi 2.txt",輸入

afew

aef(同樣到此打住)

使用"xxd 2.txt" 檢視:

0000000: 6166 6577 0a61 6566 0a afew.aef.

可以看到,第一行後邊只有一個"oa" 換行符,同時最後一行也自動增加了oa字元

現在用wc檢視下二個檔案的情況:

>wc -l 1.txt 2.txt

1 2 9 1.txt
2 2 9 2.txt
3 4 18 total

可以看到,二個檔案的字元數是一樣的,這個上邊已經分析.

使用UE轉化工具dos2unix,功用是把dos的二個切換符轉化成unix的單個字元

>dos2unix 1.txt

>wc 1.txt

1 2 8 1.txt

>xxd 1.txt

0000000: 6166 6577 0a61 6566 afew.aef

發現回車符已經被去掉了.,

同樣使用轉化工具unix2dos,功用是把unix下的單換行字元轉化為dos下的二個字元:

>unix2dos 2.txt

>wc 2.txt

2 2 11 2.txt

>xxd 2.txt

0000000: 6166 6577 0d0a 6165 660d 0a afew..aef..

可以看到,二個單換行符已經轉化成dos下的四個字元,檔案大小也多了2個字元.

現在繼續使用wc檢視下這二個檔案情況:

>wc 1.txt 2.txxt

1 2 8 1.txt
2 2 11 2.txt
3 4 19 total

現在檔案的大小問題 ,已經換行符文題已經解決了,再來關注一下unix下一些工具所受到的影響 ,仔細看可以發現一個問題 :不管是什麼格式的,在windows下生成的和在dos下生成的,行數都差一,dos下建立的檔案最後一行哪裡去了?沒有統計到嗎?

是的,的確沒統計到,wc根據行未的oa字元判斷的行數,所以結果是最後一行被忽略了.而dos2unix僅是對已有的0a/0d到oa之前的轉化,對於windows下建立的檔案進行dos2unix,也不會在最後一行裡增加oa字元,所以即使用dos2unix後,檔案wc結果也會少一行

同樣受到影響的還有while語句

>while read line; do echo $line; done <1.txt

afew

可以看到,結果也只打出了一行,


sed就不受這個的影響了:

>sed 's/a/ccc/g' 1.txt

cccfew
cccef


再試awk命令:

>awk '{print $0}' 1.txt

afew
aef

也沒有受到影響

目前常用到的shell命令,就是wc/while語句,受到影響.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/16723161/viewspace-1016821/,如需轉載,請註明出處,否則將追究法律責任。

相關文章