Windows & Unix 檔案格式之迷, 空格、回車換行、tab 轉換及其相關工具(轉載)

zhang41082發表於2019-03-30

轉載自:

本文深入揭露 Windows & Unix 格式差異, 及因此而導至的各種問題.
同時介紹了一些與之相關的檢視和操作工具, 並在 Windows, Unix 進行舉例.
1. 問題提出:
我們可能會遇到過這樣一些困惑:
(1) 如何檢視一個檔案或資料流的二進位制格式(以十六進位制格式顯示)?
(2) 為什麼在 windows下編譯的 shell 指令碼在 Unix下不能執行?
為什麼在 windows下編輯的 C 原始檔在有些 gcc 編譯器下不能編譯?
(3) 為什麼我在 vi 等編器下開啟一個文字檔案會包含 ^M, 如何把它去掉?
為什麼我在 windows 上用記事本開啟 unix上的檔案, 檔案都不換行?
(4) 如何刪除檔案行尾的 空格 或 tab?
如何把檔案中的 tab 轉換成 空格, 或者把 空格 轉換成 tab?
如何只轉換行首 tab 轉換成 空格?

[@more@]

2. 分析與方案:
(1) 如何檢視一個檔案的二進位制格式(以十六進位制格式顯示)?
檢視任意檔案或資料流的二進位制格式, 我們非常常用.
方法一: 在 UtraEdit 使用 Ctrl + H 切換到十六進位制編輯模式.
** 注意 ** :
此方法一有缺陷, 它會將行末的單個”換行符”顯示成 “回車” + “換行” 兩個字元.
這樣會使問題 (2)(3)(4) 無法用此工具正確檢視.
方法二: 使用檔案或流的二進位制檢視工具 fbin
fbin 可以執行於 windows 和各種 Unix 平臺,
如下例的命令顯示檔案的前48位元組:
$ fbin xx.c 0×30
filename: ‘xx.c’
filelen : 0×68(104), offset: 0×38, max output: 0×30
00000000: 2369 6E63 6C75 6465 3C73 7464 696F 2E68 #include00000010: 3E0D 0A0D 0A69 6E74 6D61 696E 2829 0D0A >….intmain()..
00000020: 7B0D 0A20 2020 2063 6861 7209 2020 2020 {.. char.
fbin 能準確顯示檔案中的每一個位元組. (更多詳細例項見後文)

(2) 為什麼在 windows下編輯的 shell 指令碼在 Unix下不能執行?
為什麼在 windows下編輯的 C 原始檔在有些 gcc 編譯器下不能編譯?
原因分析:
unix 的 shell 指令碼不能識別 “回車符” (即: CR, ‘r’,十六進位制顯示為0D),
Windows 檔案格式(詳細分析見下文) 換行時, 總是以 “回車” + “換行”
(可以藉助上一問介紹的 fbin 工具, 檢視檔案中是否包含 “回車換行” 對),
導到 unix 下的 shell 無法正常解釋.
解決方法:
就是把 windows 格式的中的 “回車” 符刪除, 刪除.
方法一: 使用 vi 開啟原始檔, 把 ‘rn’ 替換成 ‘n’
** 缺點 ** : 不適合大量檔案的批次作業.
方法二: 使用 UtraEdit 把 Windows 格式的檔案轉換成 Unix 格式.
(選單)檔案–>轉換–>Unix轉DOS
** 缺點 ** : 不適合大量檔案的批次作業.
方法三: Unix 下的 dos2unix 命令, 如 $ dos2unix -k xx.c
** 缺點 ** :
此方法有一致命缺陷, 它會改變原來的檔案屬性.
如一個可執行 shell 指令碼的可執行屬性及其它屬性, 轉換後都將會丟掉
(即使用 -k 也只是能保留住原來的日期.)
** 優點 ** : 適合大量普通檔案本檔案的批次作業.
方法四: win2unix (windows, unix 均可使用), 功能類似 dos2unix,
如 win2unx xx.c (更多詳細例項見後文)
** 優點** :
克服了 dos2unix 的所有缺點(見上), 它能保留原始檔的任何屬性.
還可以返回轉換即 unix2win
適合大量檔案的批次作業.

(3) 為什麼我在 vi 等編器下開啟一個文字檔案會包含 ^M, 如何把它去掉? (見結論 4, 5)
為什麼我在 windows 上用記事本開啟 unix上的檔案, 檔案都不換行? (見結論 1)
原因分析:
要解決這個問題, 必先弄清 unix 與 windows 文字檔案的差異:
1) 磁碟中 Windows 文字檔案總是以 “回車” + “換行”的形式進行換行的.
2) 磁碟中 Unix 格式的文字檔案, 總是以”換行符”(即: LF, ‘n’) 換行, 而非 “回車換行符”.
(Unix 規定: unix 文字檔案儲存到磁碟時, 總是自動把 “回車換行符” 轉換成 “回車符” 儲存,
輸出到終端時由終端自動將將 “回車符” 轉換成 “回車換行符” 輸出.)
** 容易看出 **:
Windows 格式的檔案換行時, 總是比 Unix格式的檔案多一個 “回車” (’r’) 符.這是從老式的打字機上面遺傳下來的,老式的打字機中的回車是指列印頭回到行首,換行是進紙並開始下一行列印。
** 結論 1 **:
這樣在 windows 的記事本中開啟 Unix 格式的檔案時, 因為檔案中沒有 ‘r’, 所以無法正常顯示.
結果就會把所有的內容顯示在同一行中.
** 結論 2 **:
UtraEdit 等工具會自動檢測檔案中是否包含 ‘r’, 當檢查行末缺少 ‘r’時, 一般它會提示
要求進行 Unix 到 Windows 格式的轉換. (相信大家都遇到這個提示資訊).
** 結論 3 **:
UtraEdit 和 vi 等工具, 在儲存檔案時會自動依照檔案原來的格式進行儲存. 即:
如開啟的如是 windows 格式它會把檔案依然按 windows 格式儲存 (不進行自動轉換).
如開啟的如是 unix 格式它會把檔案依然按 unix 格式儲存 (不進行自動轉換).
** 結論 4 **:
向 UtraEdit 開啟的 Unix 格式檔案中, 透過貼上板 “貼上” Windows 格式的若干片斷行時
(或反之, 即向 Windows 格式檔案中, 透過貼上板 “貼上” Unix 格式的若干片斷行時),
程式碼片斷中的 “回車換行符” “不會” 自動轉換成單個 “換行” 符(反之亦然).
這樣, 該檔案中就會出現 “回車符” 與 “回車換行符” 互相夾雜.
即, 檔案中既有單獨的 “回車符” 也有 成對的 “回車換行符”.
** 結論 5 **:
vi 編輯器等, 既能正確顯示”規則”的 Unix 格式檔案, 也能正確顯示”規則”的 Windows 格式檔案,
但, 對包含單獨的 “回車符”, 同時成對的 “回車換行符”的不規則檔案 (產生原因見結論 4),
vi 將把回車符以 ^M 的形式顯示.
解決方法:
使用類似問題 2 提供的解決方法即可解決, 不再驁述.
將 unix 轉換成 Windows 格式時, 使用 unix2dos 或 win2unix -r(-r 代表反方向)即可.

(4) 如何刪除檔案行尾的 空格 或 tab?
如何把檔案中的 tab 轉換成 空格, 或者把 空格 轉換成 tab?
如何只轉換行首 tab 轉換成 空格?
問題分析:
出於各種需要, 特別是編輯 C/C++, Java 等源程式時, 常希望將原始檔中的 tab 成空格,
或將空格轉換成 tab, 同時刪除行尾不必要的空格或 tab 等.
如果源程式的正文中字串中包含”空格”或”tab”時, 則只希望只轉換行首的”空格”或”tab”.
解決方法:
如果是單個檔案, 直接使用一些編輯器自帶的轉換功能轉換.
如果是想批次轉換, 不防試試 tab2sp 進行轉換, 不僅適合批次檔案, 還適合資料流.
方法一: 使用 UtraEdit 的轉換功能, 即: (選單)格式–>轉換 TAB 為空格, …
** 缺點 **:
不適合大量檔案的批次作業.
方法二: tab2sp (適合 windows, 各種 unix 平臺),
如 tab2sp -t -w8 xx.c (更多詳細例項見後文)
** 優點 **:
適合大量檔案的批次作業.
適應檔案或流的二進位制檢視工具 fbin

3. 工具詳解: fbin, win2unix, tab2sp 等對流或檔案進行批次檢視/轉換
(1) 工具簡介
fbin, win2unix, tab2sp 等工具對流或檔案進行批次檢視/轉換,
適合 Windows 和 各種 Unix 平臺.
(2) fbin - 檢視流/檔案的二進位制格式
在命令列上鍵入下面命令即可檢視線上幫助(部分內容未列出)
$ fbin –help
fbin - display file with hex format, version 1.0.4
Copyright(C) eyBuild Group, 2005, 2006. All Rights Reserved.
,
Usage: fbin [options] [fname [0x][offset] [maxlen] | [file1] …]
-h –help - show this help
-w[num] - specify word-width [2/4], default 2
-p - pause for every screen
-v - verbose mode
-l - process file list replace ‘fname’ …
fname - file name to display
offset - hex number, ‘0x’ is optional.
offset >= 0 from the begining of input file,
offset < 0 from the end of input file
maxlen - max length to print
EXAMPLES:
win2unix -p foo.bin
print at most 64 (0×40) bytes from offset 0×200:
fbin foo.bin 0×200 0×40
print last 32 (0×20) bytes with 4-bytes word-width:
fbin -w4 foo.bin -20
process file list:
fbin -v -l f1 f2 f3 f4 f5 f6
例1. 檢視一個檔案前 64 個位元組二進位制:
(Unix/Windos 執行下面命令會得到相同結果)
$ fbin fbin.c 0 40
00000000: 2F2A 2066 6269 6E2E 6320 2D20 6C69 7374 /* fbin.c - list
00000010: 2066 696C 6520 7769 7468 2062 696E 6E61 file with binna
00000020: 7279 2066 6F72 6D61 7420 2A2F 0A0A 2F2A ry format */../*
00000030: 2043 6F70 7972 6967 6874 2843 2920 6579 Copyright(C) ey
例2. 檢視一個檔案最後 64 個位元組二進位制:
(Unix/Windos 執行下面命令會得到相同結果)
$ fbin fbin.c -40
000022D5: 2020 2061 7267 632D 2D2C 2061 7267 762B argc–, argv+
000022E5: 2B3B 0A20 2020 2020 2020 2067 6F74 6F20 +;. goto
000022F5: 4E45 5854 3B0A 2020 2020 7D0A 0A20 2020 NEXT;. }..
00002305: 2072 6574 7572 6E20 4F4B 3B0A 7D0A 0A0A return OK;.}…
例3. 檢視一個檔案從 128 位元組開始的 64 個位元組二進位制 (4 位元組寬度):
(Unix/Windos 執行下面命令會得到相同結果)
$ fbin -w4 fbin.c 40 40
00000040: 4275696C 64204772 6F75702C 20323030 Build Group, 200
00000050: 352C2032 3030362E 20416C6C 20526967 5, 2006. All Rig
00000060: 68747320 52657365 72766564 2E202A2F hts Reserved. */
00000070: 0A0A2F2A 0A6D6F64 69666963 6174696F ../*.modificatio
例4. 批次顯示查詢(包含子目錄)到的所有檔案 (4 位元組寬度):
Unix 命令:
$ find ../bin -name “*.exe” | xargs fbin -w4 -l -v |less
filename: ‘../bin/csp2bin.exe’
filelen : 0×18000(98304)
00000000: 4D5A9000 03000000 04000000 FFFF0000 MZ…………..
00000010: B8000000 00000000 40000000 00000000 ……..@…….
00000020: 00000000 00000000 00000000 00000000 …………….
00000030: 00000000 00000000 00000000 E0000000 …………….
00000040: 0E1FBA0E 00B409CD 21B8014C CD215468 ……..!..L.!Th
00000050: 69732070 726F6772 616D2063 616E6E6F is program canno
00000060: 74206265 2072756E 20696E20 444F5320 t be run in DOS
00000070: 6D6F6465 2E0D0D0A 24000000 00000000 mode….$…….
00000080: 08A64111 4CC72F42 4CC72F42 4CC72F42 ..A.L./BL./BL./B
00000090: 37DB2342 4EC72F42 7AE12442 4DC72F42 7.#BN./Bz.$BM./B
000000A0: CFDB2142 59C72F42 2ED83C42 4FC72F42 ..!BY./B..000000B0: 4CC72E42 0FC72F42 7AE12542 26C72F42 L..B../Bz.%B&./B
000000C0: 52696368 4CC72F42 00000000 00000000 RichL./B……..
000000D0: 00000000 00000000 00000000 00000000 …………….
000000E0: 50450000 4C010300 3642A445 00000000 PE..L…6B.E….
000000F0: 00000000 E0000F01 0B010600 00000100 …………….
00000100: 00901000 00000000 F5A80000 00100000 …………….
00000110: 00100100 00004000 00100000 00100000 ……@………

Windos 命令如下命令, 會得到相同結果:
E:> for /F %I in (’dir /w /b /s /A:-D eybuildbin’) do fbin -w2 -v -l %I | more
(3) win2unix - Windows 與 Unix 檔案格式互轉換工具
在命令列上鍵入下面命令即可檢視線上幫助(部分內容未列出)
$ win2unix –help
win2unix - translate file between windows and unix format, version 1.0.5
Usage: win2unix [options] [[src] [dst] | [file1] …]
-h –help - show this help
-r - translate file from unix format to windows
-v - verbose mode
-l - process file list replace ’src’ & ‘dst’ pair
src - source file or dectory
dst - destination file or dectory
EXAMPLES:
win2unix foo.txt
convert unix to windows format:
win2unix -r -b src.txt dst.txt
process file list:
win2unix -v -l f1 f2 f3 f4 f5 f6
例1. Unix 格式轉換成 Windows 格式:
$ win2unx -r fbin.c
檢視二進位制結果如下, 與fbin中的”例1″對比容易發現, 第3行中原來的0A0A(兩個”換行符”)
被轉換成了 0D0A0D0A (兩對”回車換行符”).
$ fbin fbin.c 0 40
00000000: 2F2A 2066 6269 6E2E 6320 2D20 6C69 7374 /* fbin.c - list
00000010: 2066 696C 6520 7769 7468 2062 696E 6E61 file with binna
00000020: 7279 2066 6F72 6D61 7420 2A2F 0D0A 0D0A ry format */….
00000030: 2F2A 2043 6F70 7972 6967 6874 2843 2920 /* Copyright(C)
例2. Windows 格式轉換成 Unix 格式:
$ win2unx fbin.c
檢視二進位制結果如下, 與 “例1″對比容易發現, 第3行中原來的0D0A0D0A (兩對”回車換行符”)
被轉換成了 0A0A(兩個”換行符”)
$ fbin fbin.c 0 40
00000000: 2F2A 2066 6269 6E2E 6320 2D20 6C69 7374 /* fbin.c - list
00000010: 2066 696C 6520 7769 7468 2062 696E 6E61 file with binna
00000020: 7279 2066 6F72 6D61 7420 2A2F 0A0A 2F2A ry format */../*
00000030: 2043 6F70 7972 6967 6874 2843 2920 6579 Copyright(C) ey
例3. 批次轉換查詢(包含子目錄)到的所有檔案:
$ find src -name “*.c” | xargs win2unix -l -v
convert ‘win’ to ‘unix’ format …
src/csp2bin.c
src/tab2sp.c
src/fbin.c
src/win2unix.c

Windos 命令如下命令, 會得到相同結果:
E:> for /F %I in (’dir /w /b /s /A:-D src/*.c’) do win2unix -v -l %I
(4) tab2sp - tab 與 空格的互轉換
在命令列上鍵入下面命令即可檢視線上幫助(部分內容未列出)
$ win2unix –help
tab2sp - convert tabs to spaces or revert, version 1.0.2
Usage: tab2sp [options] [[src] [dst] | [file1] …]
-h –help - show this help
-r - convert spaces to tabs
-p - only convert line prefixed spaces or tabs
-t - remove tail tabs and spaces
-w[num] - specify tab width [1-8], default 4
-no - don’t do any convert
-v - verbose mode
-l - process file list replace ’src’ & ‘dst’ pair
src - source file
dst - destination file
EXAMPLES:
tab2sp -r < foo.txt
convert tabs to spaces:
tab2sp foo.txt
convert spaces to tabs and remove tail tabs, spaces:
tab2sp -r -t foo.txt
only remove tail tabs and spaces:
tab2sp -no -t foo.txt
process file list:
tab2sp -v -l f1 f2 f3 f4 f5 f6
例1. 將檔案中的所 tab 轉換成 “空格”(預設 4 字元寬度), 並刪除尾部 tab 和空格:
$ tab2sp -t fbin.c
可自行用 fbin 檢視二進位制結果如下, 確認是否 tab(09) 全部轉成成了空格(20).
本處不再把示例結果列出.
例2. 將檔案中的所 “空格” 轉換成 tab (預設 4 字元寬度), 並刪除尾部 tab 和空格:
$ tab2sp -r -t fbin.c
例3. 將檔案中的所 tab 轉換成空格(指定為 8 字元寬度), 並刪除尾部 tab 和空格:
$ tab2sp -t -w8 fbin.c
例4. 只刪除檔案 f1, f2, f3 f4 行尾的空格
$ tab2sp -no -t -l f1 f2 f3 f4
例5. 只轉換行首 tab 為空格(指定為 8 字元寬度), 並刪除尾部 tab 和空格:
$ tab2sp -p -t -l f1 f2 f3 f4
例6. 批次轉換查詢(包含子目錄)到的所有檔案, 命令可以自由組合:
$ find src -name “*.c” | xargs tab2sp -l -v -w8 -p
convert ‘tab’ to ’space’ format …
src/csp2bin.c
src/tab2sp.c
src/fbin.c
src/win2unix.c

Windos 命令如下命令, 會得到相同結果:
E:> for /F %I in (’dir /w /b /s /A:-D src/*.c’) do tab2sp -l -v -w8 -p %I

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

相關文章