最近在搞Unix Shell的東西,在這個過程中看了不少書籍資料,也受了不少折騰,因此這裡把一些需要注意的細節記錄下來以作備忘和提醒。這裡的Shell是指Bourne Shell,其它類型的Shell我沒有用過因此不知道是否存在相同問題。另外Unix Shell的基礎資料這裡也不多介紹,其實網上的相關資料是比較散,加之Shell本身牽扯的東西也比較多,其中包括Unix的系統知識,不同版本Shell的文法和功能,Regex,管道什麼,要一次說清楚也不容易。這裡推薦一本書《UNIX shell範例精解》,在學習Shell的過程中它確實幫了不少忙。好,開始備忘~
1、關於環境變數
環境變數的範圍是由上到下的,並且在子進程裡改變了環境變數是不會傳遞迴父進程。因此在全域使用的環境變數應該在父進程裡定義,子進程或者其它進程定義的環境變數不會能共用訪問。環境變數的這個特性對Shell程式的結構有很大的影響。因為如果要使用環境變數作為全域變數使用,那麼Shell指令碼程式之間就必須保持一種至上向下的調用關係。
Shell裡面沒有全域變數的概念,只有環境變數和局部變數。全域變數的解決方案有這麼幾種:
a.使Shell指令碼之間保持一個至上向下的調用關係,然後在父進程中定義環境變數;
b.使用唯讀局部變數,然後保證所有指令碼在同一進程下執行;
c.儲存變數在一個config檔案內,指令碼執行載入;
或者這裡說到的全域變數有點常量的味道,畢竟全域變數是可以在過程之間共用資訊的,但是上面提及的方法都不可以。如果要過程之間通訊估計只有通過參數和傳回值了。真正意義上的全域變數怎麼實現暫不做探討(因為我還沒有這個需求,嘻嘻)
其實把環境變數載入到Unix的主進程中也可以把它直接當全域變數使用,這個方法是第一個方案的特殊使用。
2、使用“.”呼叫指令碼最好放在接收參數之後,不然可能會引起“$#”這些特殊變數的值的改變
3、if語句中使用“[]”替換test時,要注意“[]”使用是的空格,例如:if [ "$a" != "" ] then #空格不能省略
4、cp -R 時,要注意目標路徑中不需要提供複製後的目錄名,例如:cp -R /a /b/ 這樣將會把a目錄複寫到b目錄中,複製後的目錄仍叫a(此處與xcopy有差別)
另外,cp並不會自動建立目標目錄。
5、使用while讀取檔案時要注意
當使用
while read line
do
#####
done < file
讀取檔案時,發現檔案最後一行不會在while內讀取。這個問題不知道是不是上面代碼的寫法問題....
6、“()”“{}”的特殊作用
留意以下取得指令碼所在路徑的方法:currdir=$(cd "$(dirname "$0")"; pwd)
這個語句的作用是返回當前執行指令碼的所在路徑,而不是執行路徑。其中“()”的意思為將dirname、cd、pwd等幾個命令作為子進程執行,但不將改變進程的上下文。從上面的例子來分析,因為有兩個嵌套的括弧,指令碼先執行$(dirname "$0")。$0為當前執行指令碼的名稱,dirname $0為取得指令碼所在的路徑(絕對或相對路徑,這個取決於你怎樣調用執行指令碼)。$(cd "**"; pwd),嵌套外語句作用的很明顯,就是進入某個路徑,然後返回該路徑的絕對路徑。前面提到“()”是隔斷內容相關的。所以$(cd "**"; pwd)這裡的cd命令並不會改變執行指令碼的當前路徑。整個語句的原理就大概是這麼一回事。
說回來,“()”的作用就是將語句編組為語句塊,然後啟動子進程運行該語句塊,子進程改變的上下文不會被傳遞迴當前進程。
而“{}”的作用與“()”類似,但是它是回將內容相關的改變傳遞會當前進程的,更直接的說就是,“{}”與當前進程使用同一個進程環境。
7、注意windows和unix檔案格式的區別
windows裡面,檔案的行識別符是"\r\n",在Unix中,是“\n”。如果shell指令碼使用了,windows格式,將不能運行。如果指令碼使用設定檔,在格式問題也會影響指令碼識別設定檔字串。
8、grep、awk、sed是很強大的命令,將他們和其它命令,通過管道組合起來,可以完成很多複雜的任務。
9、一些Shell相關資料和手冊:
R2's Shell Tutorials
http://www.injunea.demon.co.uk/index.htm
Unix Power Tools
" href="http://docstore.mik.ua/orelly/unix/upt/index.htm">http://docstore.mik.ua/orelly/unix/upt/index.htm