從一個shell指令碼執行出錯聊起

realkid4發表於2014-01-13

 

運維人員面對的環境是複雜的。僅就作業系統而言,就有Windows ServerUnixAIX和各種分支伺服器OS。由於系統環境的差異,運維人員是很難做到知識面面俱到,對所有的特性瞭如指掌。這個時候,個人發展的方向性和堅持精神就十分重要。一點點的積累,從一些小問題著手,個人才能慢慢的成長。

AIX/LinuxWindows在體系架構、檔案系統等方面的差異多如牛毛。本篇從一個執行錯誤的shell指令碼入手,討論一個簡單的文字差異特性。

 

1、問題出現

 

一個同事在編寫備份Shell指令碼時,遇到了報錯資訊如下。

 

從一個shell指令碼執行出錯聊起

 

報錯是比較奇怪的。指令碼命令是參考現成執行指令碼編寫的,不會有過多的語法語義錯誤。更有甚者,一些報錯行(如2226)指令碼中都是空行。空行為什麼會出現報錯資訊?

 

2、文字結尾差異

 

這種情況,通常是遇到了文字行結尾差異問題。ASCII格式是我們非常常用的格式型別。從Linux中大量配置檔案,到各型別應用系統的日誌檔案,我們都可以看到ASCII格式文字的身影。

經常使用AIX/Unix環境的朋友可能會有這樣的經歷:如果我們將AIX/Unix環境建立的檔案傳遞到Windows平臺,使用“記事本”軟體開啟,就會發現所有的換行標記都轉化為黑點,而且換行資料全部被設定為一行。

解決這種混亂,比較好的方法是使用專業的工具如UlterEdit或者寫字板開啟,換行標記可以識別正確。

究其原因,本質上是由於兩種作業系統平臺對於換行標記差異造成的。Unix/AIX中,換行標記是Line Feed(也就是經常出現的LF)。而在Windows環境中,換行回車標記為一個Line Feed外加一個Carriage ReturnCR)。無論是LF還是CR,都反映在ASCII格式的檔案字元中。

在很多情況下,換行字元是檔案進行跨平臺經常出故障的地方。如果我們在Windows環境下儲存一個文字檔案,那麼拿到AIX/Unix環境下,讀取過程就會出現一個多餘的^M字元,從而報錯。這也就是同事遇到問題的本質原因。

經過詢問,同事指令碼的確進行過Windows環境的編輯儲存動作。並且是使用預設的記事本報錯。

那麼,如何處理這樣的問題呢?

 

3Utl_File輸出的檔案回車符

 

聊解決辦法之前,我們先看看PL/SQL程式包utl_file。程式UTL_FILE歷史很久,可以追溯到早期的Oracle版本。UTL_FILE用於在Server端指定目錄上輸出ASCII格式文字。其效能和簡單特性給很多應用程式提供了檔案輸出介面。

那麼,Utl_file在換行符問題上,是如何處理的呢?Oracle這裡採用的策略是“隨行就市”。不同的作業系統平臺,put_line的時候生成不同換行標記。下面我們做一個小實驗,來證明這點。實驗Oracle 11gR2測試。

 

SQL> select * from v$version;

BANNER

----------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - Production

PL/SQL Release 11.2.0.3.0 - Production

CORE 11.2.0.3.0 Production

TNS for Linux: Version 11.2.0.3.0 - Production

NLSRTL Version 11.2.0.3.0 – Production

 

建立directoryPL/SQL指令碼片段。

 

SQL> create directory file_dir as '/tmp';

Directory created

 

SQL> declare

  2    file_info utl_file.file_type;

  3  begin

  4    file_info := utl_file.fopen('FILE_DIR','test.log','w');

  5    utl_file.put_line(file_info,'This is line 1');

  6    utl_file.put_line(file_info,'This is line 2');

  7    utl_file.put_line(file_info,'This is line 3');

  8    utl_file.fclose(file_info);

  9  end;

 10  /

PL/SQL procedure successfully completed

 

Linux環境中,我們可以看到正確的換行資料。

 

[oracle@SimpleLinux tmp]$ pwd

/tmp

[oracle@SimpleLinux tmp]$ ls -l | grep test

-rw-r--r-- 1 oracle oinstall   45 Jan 10 10:52 test.log

[oracle@SimpleLinux tmp]$ cat test.log

This is line 1

This is line 2

This is line 3

 

但是我們使用FTP/SFTP將原來檔案下載到Windows本地,使用記事本軟體開啟文字,發現換行符問題。

 

從一個shell指令碼執行出錯聊起

 

說明,utl_file輸出檔案的時候,是按照Server端的環境配置來設定換行資訊的。如果我們在Windows伺服器上執行,想必也是Windows的換行方式。

這也引起了一個問題,我們使用utl_file包生成介面檔案,是在一定的作業系統平臺基礎上。如果是Linux/AIX生成的檔案,那麼接收方一定也要是Linux/AIX環境才能正確接受。注意:一些文獻中聲稱使用ASCII格式FTP傳輸檔案,可以實現換行符的自動切換。這樣是比較方便的,但是筆者沒有測試成功。

Windows平臺上,遇到這樣的問題,我們是使用UltreEdit等編輯器軟體儲存為Unix換行標記才行。在Linux平臺上,有一些命令可以幫助我們這種轉換。

 

4unix2dosdos2unix

 

Linux中,特別提供了配對命令工具unix2dosdos2unix,用於進行兩種格式的轉換。

Unix2dos用於將Unix格式轉化為Windows格式,其中的回車符也是支援轉換的。使用我們之前建立的test.log檔案。

 

[oracle@SimpleLinux tmp]$ unix2dos test.log

unix2dos: converting file test.log to DOS format ...

 

換行符正常,複製到Windows環境中檢視。

 

從一個shell指令碼執行出錯聊起

 

同理dos2unix可以實現從dos格式轉化為unix。針對我們的程式指令碼,進行處理。

 

[oracle@SimpleLinux tmp]$ dos2unix hot_xxx_change2.sh

dos2unix: converting file hot_xxx_change2.sh to UNIX format ...

[oracle@SimpleLinux tmp]$

 

windows環境上,我們可以看到這種變化。

 

從一個shell指令碼執行出錯聊起

 

試驗成功。

 

5、結論

 

字符集是無論運維還是開發都不容易處理、而且不能避免的老問題。透過這個案例,我們瞭解了Oracle和作業系統回車字元的特點和功能差異,記錄下來,供有需要的朋友不時之需。


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

相關文章