Shell的基本語法

Shell的基本語法 

3.1. 變量 

按照慣例,Shell變量由全大寫字母加下劃線組成,有兩種類型的Shell變量:

環境變量

第 2 節 “環境變量”中講過,環境變量可以從父進程傳給子進程,因此Shell進程的環境變量可以從當前Shell進程傳給fork出來的子進程。用printenv命令可以顯示當前Shell進程的環境變量。

本地變量

只存在於當前Shell進程,用set命令可以顯示當前Shell進程中定義的所有變量(包括本地變量和環境變量)和函數。

環境變量是任何進程都有的概念,而本地變量是Shell特有的概念。在Shell中,環境變量和本地變量的定義和用法相似。在Shell中定義或賦值一個變量:

$ VARNAME=value

注意等號兩邊都不能有空格,否則會被Shell解釋成命令和命令行參數。

一個變量定義後僅存在於當前Shell進程,它是本地變量,用export命令可以把本地變量導出爲環境變量,定義和導出環境變量通常可以一步完成:

$ export VARNAME=value

也可以分兩步完成:

$ VARNAME=value $ export VARNAME

unset命令可以刪除已定義的環境變量或本地變量。

$ unset VARNAME

如果一個變量叫做VARNAME,用${VARNAME}可以表示它的值,在不引起歧義的情況下也可以用$VARNAME表示它的值。通過以下例子比較這兩種表示法的不同:

$ echo $SHELL $ echo $SHELLabc $ echo $SHELL abc $ echo ${SHELL}abc

注意,在定義變量時不用$,取變量值時要用$。和C語言不同的是,Shell變量不需要明確定義類型,事實上Shell變量的值都是字符串,比如我們定義VAR=45,其實VAR的值是字符串45而非整數。Shell變量不需要先定義後使用,如果對一個沒有定義的變量取值,則值爲空字符串。

3.2. 文件名代換(Globbing):* ? [] 

這些用於匹配的字符稱爲通配符(Wildcard),具體如下:

表 31.1. 通配符

* 匹配0個或多個任意字符
? 匹配一個任意字符
[若干字符] 匹配方括號中任意一個字符的一次出現

$ ls /dev/ttyS* $ ls ch0?.doc $ ls ch0[0-2].doc $ ls ch[012][0-9].doc

注意,Globbing所匹配的文件名是由Shell展開的,也就是說在參數還沒傳給程序之前已經展開了,比如上述ls ch0[012].doc命令,如果當前目錄下有ch00.docch02.doc,則傳給ls命令的參數實際上是這兩個文件名,而不是一個匹配字符串。

3.3. 命令代換:`或 $() 

由反引號括起來的也是一條命令,Shell先執行該命令,然後將輸出結果立刻代換到當前命令行中。例如定義一個變量存放date命令的輸出:

$ DATE=`date` $ echo $DATE

命令代換也可以用$()表示:

$ DATE=$(date)

3.4. 算術代換:$(()) 

用於算術計算,$(())中的Shell變量取值將轉換成整數,例如:

$ VAR=45 $ echo $(($VAR+3))

$(())中只能用+-*/和()運算符,並且只能做整數運算。

3.5. 轉義字符\ 

和C語言類似,\在Shell中被用作轉義字符,用於去除緊跟其後的單個字符的特殊意義(回車除外),換句話說,緊跟其後的字符取字面值。例如:

$ echo $SHELL /bin/bash $ echo \$SHELL $SHELL $ echo \\ \

比如創建一個文件名爲“$ $”的文件可以這樣:

$ touch \$\ \$

還有一個字符雖然不具有特殊含義,但是要用它做文件名也很麻煩,就是-號。如果要創建一個文件名以-號開頭的文件,這樣是不行的:

$ touch -hello touch: invalid option -- h Try `touch --help' for more information.

即使加上\轉義也還是報錯:

$ touch \-hello touch: invalid option -- h Try `touch --help' for more information.

因爲各種UNIX命令都把-號開頭的命令行參數當作命令的選項,而不會當作文件名。如果非要處理以-號開頭的文件名,可以有兩種辦法:

$ touch ./-hello

或者

$ touch -- -hello

\還有一種用法,在\後敲回車表示續行,Shell並不會立刻執行命令,而是把光標移到下一行,給出一個續行提示符>,等待用戶繼續輸入,最後把所有的續行接到一起當作一個命令執行。例如:

$ ls \ > -l (ls -l命令的輸出)

3.6. 單引號 

和C語言不一樣,Shell腳本中的單引號和雙引號一樣都是字符串的界定符(雙引號下一節介紹),而不是字符的界定符。單引號用於保持引號內所有字符的字面值,即使引號內的\和回車也不例外,但是字符串中不能出現單引號。如果引號沒有配對就輸入回車,Shell會給出續行提示符,要求用戶把引號配上對。例如:

$ echo '$SHELL' $SHELL $ echo 'ABC\(回車) > DE'(再按一次回車結束命令) ABC\ DE

3.7. 雙引號 

雙引號用於保持引號內所有字符的字面值(回車也不例外),但以下情況除外:

  • $加變量名可以取變量的值

  • 反引號仍表示命令替換

  • \$表示$的字面值

  • \`表示`的字面值

  • \"表示"的字面值

  • \\表示\的字面值

  • 除以上情況之外,在其它字符前面的\無特殊含義,只表示字面值

$ echo "$SHELL" /bin/bash $ echo "`date`" Sun Apr 20 11:22:06 CEST 2003 $ echo "I'd say: \"Go for it\"" I'd say: "Go for it" $ echo "\"(回車) >"(再按一次回車結束命令) "  $ echo "\\" \

4. bash啓動腳本 請點評

啓動腳本是bash啓動時自動執行的腳本。用戶可以把一些環境變量的設置和aliasumask設置放在啓動腳本中,這樣每次啓動Shell時這些設置都自動生效。思考一下,bash在執行啓動腳本時是以fork子Shell方式執行的還是以source方式執行的?

啓動bash的方法不同,執行啓動腳本的步驟也不相同,具體可分爲以下幾種情況。

4.1. 作爲交互登錄Shell啓動,或者使用--login參數啓動 請點評

交互Shell是指用戶在提示符下輸命令的Shell而非執行腳本的Shell,登錄Shell就是在輸入用戶名和密碼登錄後得到的Shell,比如從字符終端登錄或者用telnet/ssh從遠程登錄,但是從圖形界面的窗口管理器登錄之後會顯示桌面而不會產生登錄Shell(也不會執行啓動腳本),在圖形界面下打開終端窗口得到的Shell也不是登錄Shell。

這樣啓動bash會自動執行以下腳本:

  1. 首先執行/etc/profile,系統中每個用戶登錄時都要執行這個腳本,如果系統管理員希望某個設置對所有用戶都生效,可以寫在這個腳本里

  2. 然後依次查找當前用戶主目錄的~/.bash_profile~/.bash_login~/.profile三個文件,找到第一個存在並且可讀的文件來執行,如果希望某個設置只對當前用戶生效,可以寫在這個腳本里,由於這個腳本在/etc/profile之後執行,/etc/profile設置的一些環境變量的值在這個腳本中可以修改,也就是說,當前用戶的設置可以覆蓋(Override)系統中全局的設置。~/.profile這個啓動腳本是sh規定的,bash規定首先查找以~/.bash_開頭的啓動腳本,如果沒有則執行~/.profile,是爲了和sh保持一致。

  3. 順便一提,在退出登錄時會執行~/.bash_logout腳本(如果它存在的話)。

4.2. 以交互非登錄Shell啓動 請點評

比如在圖形界面下開一個終端窗口,或者在登錄Shell提示符下再輸入bash命令,就得到一個交互非登錄的Shell,這種Shell在啓動時自動執行~/.bashrc腳本。

爲了使登錄Shell也能自動執行~/.bashrc,通常在~/.bash_profile中調用~/.bashrc

if [ -f ~/.bashrc ]; then     . ~/.bashrc fi

這幾行的意思是如果~/.bashrc文件存在則source它。多數Linux發行版在創建帳戶時會自動創建~/.bash_profile~/.bashrc腳本,~/.bash_profile中通常都有上面這幾行。所以,如果要在啓動腳本中做某些設置,使它在圖形終端窗口和字符終端的Shell中都起作用,最好就是在~/.bashrc中設置。

下面做一個實驗,在~/.bashrc文件末尾添加一行(如果這個文件不存在就創建它):

export PATH=$PATH:/home/akaedu

然後關掉終端窗口重新打開,或者從字符終端logout之後重新登錄,現在主目錄下的程序應該可以直接輸程序名運行而不必輸入路徑了,例如:

~$ a.out

就可以了,而不必

~$ ./a.out

爲什麼登錄Shell和非登錄Shell的啓動腳本要區分開呢?最初的設計是這樣考慮的,如果從字符終端或者遠程登錄,那麼登錄Shell是該用戶的所有其它進程的父進程,也是其它子Shell的父進程,所以環境變量在登錄Shell的啓動腳本里設置一次就可以自動帶到其它非登錄Shell裏,而Shell的本地變量、函數、alias等設置沒有辦法帶到子Shell裏,需要每次啓動非登錄Shell時設置一遍,所以就需要有非登錄Shell的啓動腳本,所以一般來說在~/.bash_profile裏設置環境變量,在~/.bashrc裏設置本地變量、函數、alias等。如果你的Linux帶有圖形系統則不能這樣設置,由於從圖形界面的窗口管理器登錄並不會產生登錄Shell,所以環境變量也應該在~/.bashrc裏設置。

4.3. 非交互啓動 請點評

爲執行腳本而fork出來的子Shell是非交互Shell,啓動時執行的腳本文件由環境變量BASH_ENV定義,相當於自動執行以下命令:

if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi

如果環境變量BASH_ENV的值不是空字符串,則把它的值當作啓動腳本的文件名,source這個腳本。

4.4. 以sh命令啓動 請點評

如果以sh命令啓動bashbash將模擬sh的行爲,以~/.bash_開頭的那些啓動腳本就不認了。所以,如果作爲交互登錄Shell啓動,或者使用--login參數啓動,則依次執行以下腳本:

  1. /etc/profile

  2. ~/.profile

如果作爲交互Shell啓動,相當於自動執行以下命令:

if [ -n "$ENV" ]; then . "$ENV"; fi

如果作爲非交互Shell啓動,則不執行任何啓動腳本。通常我們寫的Shell腳本都以#!/bin/sh開頭,都屬於這種方式。



http://blog.163.com/bobile45@126/blog/static/9606199220126264495372/


發佈了74 篇原創文章 · 獲贊 17 · 訪問量 64萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章