從一個shell指令碼執行出錯聊起
運維人員面對的環境是複雜的。僅就作業系統而言,就有Windows Server、Unix、AIX和各種分支伺服器OS。由於系統環境的差異,運維人員是很難做到知識面面俱到,對所有的特性瞭如指掌。這個時候,個人發展的方向性和堅持精神就十分重要。一點點的積累,從一些小問題著手,個人才能慢慢的成長。
AIX/Linux和Windows在體系架構、檔案系統等方面的差異多如牛毛。本篇從一個執行錯誤的shell指令碼入手,討論一個簡單的文字差異特性。
1、問題出現
一個同事在編寫備份Shell指令碼時,遇到了報錯資訊如下。
報錯是比較奇怪的。指令碼命令是參考現成執行指令碼編寫的,不會有過多的語法語義錯誤。更有甚者,一些報錯行(如22、26)指令碼中都是空行。空行為什麼會出現報錯資訊?
2、文字結尾差異
這種情況,通常是遇到了文字行結尾差異問題。ASCII格式是我們非常常用的格式型別。從Linux中大量配置檔案,到各型別應用系統的日誌檔案,我們都可以看到ASCII格式文字的身影。
經常使用AIX/Unix環境的朋友可能會有這樣的經歷:如果我們將AIX/Unix環境建立的檔案傳遞到Windows平臺,使用“記事本”軟體開啟,就會發現所有的換行標記都轉化為黑點,而且換行資料全部被設定為一行。
解決這種混亂,比較好的方法是使用專業的工具如UlterEdit或者寫字板開啟,換行標記可以識別正確。
究其原因,本質上是由於兩種作業系統平臺對於換行標記差異造成的。在Unix/AIX中,換行標記是Line Feed(也就是經常出現的LF)。而在Windows環境中,換行回車標記為一個Line Feed外加一個Carriage Return(CR)。無論是LF還是CR,都反映在ASCII格式的檔案字元中。
在很多情況下,換行字元是檔案進行跨平臺經常出故障的地方。如果我們在Windows環境下儲存一個文字檔案,那麼拿到AIX/Unix環境下,讀取過程就會出現一個多餘的^M字元,從而報錯。這也就是同事遇到問題的本質原因。
經過詢問,同事指令碼的確進行過Windows環境的編輯儲存動作。並且是使用預設的記事本報錯。
那麼,如何處理這樣的問題呢?
3、Utl_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
建立directory和PL/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本地,使用記事本軟體開啟文字,發現換行符問題。
說明,在utl_file輸出檔案的時候,是按照Server端的環境配置來設定換行資訊的。如果我們在Windows伺服器上執行,想必也是Windows的換行方式。
這也引起了一個問題,我們使用utl_file包生成介面檔案,是在一定的作業系統平臺基礎上。如果是Linux/AIX生成的檔案,那麼接收方一定也要是Linux/AIX環境才能正確接受。注意:一些文獻中聲稱使用ASCII格式FTP傳輸檔案,可以實現換行符的自動切換。這樣是比較方便的,但是筆者沒有測試成功。
在Windows平臺上,遇到這樣的問題,我們是使用UltreEdit等編輯器軟體儲存為Unix換行標記才行。在Linux平臺上,有一些命令可以幫助我們這種轉換。
4、unix2dos和dos2unix
在Linux中,特別提供了配對命令工具unix2dos和dos2unix,用於進行兩種格式的轉換。
Unix2dos用於將Unix格式轉化為Windows格式,其中的回車符也是支援轉換的。使用我們之前建立的test.log檔案。
[oracle@SimpleLinux tmp]$ unix2dos test.log
unix2dos: converting file test.log to DOS format ...
換行符正常,複製到Windows環境中檢視。
同理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環境上,我們可以看到這種變化。
試驗成功。
5、結論
字符集是無論運維還是開發都不容易處理、而且不能避免的老問題。透過這個案例,我們瞭解了Oracle和作業系統回車字元的特點和功能差異,記錄下來,供有需要的朋友不時之需。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17203031/viewspace-1070126/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 執行shell指令碼指令碼
- crontab執行shell指令碼指令碼
- shell指令碼執行錯誤 $‘\r‘:command not found指令碼
- 執行Shell指令碼的方式指令碼
- 執行Shell指令碼的方式(轉)指令碼
- Mac 終端執行 shell 指令碼Mac指令碼
- shell入門--第一個shell指令碼指令碼
- bash shell指令碼執行方法總結指令碼
- 使用CRONTAB呼叫shell指令碼執行EXP指令碼
- Linux下如何執行Shell指令碼Linux指令碼
- Linux shell:執行shell指令碼的幾種方式Linux指令碼
- Linux Shell程式設計(3)——執行shell指令碼Linux程式設計指令碼
- sh指令碼執行報錯指令碼
- 執行shell指令碼報錯:-bash: ./test1.sh: /bin/bash^M: ...指令碼
- 如何在 Shell 指令碼中執行語法檢查除錯模式指令碼除錯模式
- 執行 shell 指令碼 \r 問題解決指令碼
- shell指令碼linux命令連續執行指令碼Linux
- shell指令碼的執行環境變數指令碼變數
- PHP 避免同時執行一個指令碼PHP指令碼
- 分享一個shell指令碼的坑:grep匹配+wc取值 在指令碼執行後的結果與手動執行結果不一致指令碼
- 使用Mac自定義快捷鍵執行shell指令碼Mac指令碼
- php執行shell指令碼需要sudo許可權PHP指令碼
- 前端釋出shell指令碼前端指令碼
- 一個比較好的shell指令碼指令碼
- shell指令碼報錯:[: missing `]‘指令碼
- 執行指令碼diagcollection.pl報錯指令碼GC
- 如何讓shell指令碼變成可執行檔案指令碼
- Shell指令碼入門:編寫格式與執行方式指令碼
- 通過shell指令碼監控sql執行頻率指令碼SQL
- 透過shell指令碼監控sql執行頻率指令碼SQL
- 一個“指令碼執行夯死”問題的分析指令碼
- 共享一個iptables的shell指令碼檔案指令碼
- 向大家分享一個shell指令碼的坑指令碼
- 如何用crontab每隔1分鐘執行一個命令列指令碼,shell設定時任務命令列指令碼
- shell 指令碼的除錯問題指令碼除錯
- shell指令碼報錯:"[: =: unary operator expected"指令碼
- Linux Bash Shell學習(七):shell程式設計基礎——執行Shell指令碼、functionLinux程式設計指令碼Function
- shell指令碼命令 執行python檔案&python命令列執行python程式碼指令碼Python命令列