Shell的基本語法
按照慣例,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變量不需要先定義後使用,如果對一個沒有定義的變量取值,則值爲空字符串。
這些用於匹配的字符稱爲通配符(Wildcard),具體如下:
$ ls /dev/ttyS* $ ls ch0?.doc $ ls ch0[0-2].doc $ ls ch[012][0-9].doc
注意,Globbing所匹配的文件名是由Shell展開的,也就是說在參數還沒傳給程序之前已經展開了,比如上述ls ch0[012].doc
命令,如果當前目錄下有ch00.doc
和ch02.doc
,則傳給ls
命令的參數實際上是這兩個文件名,而不是一個匹配字符串。
由反引號括起來的也是一條命令,Shell先執行該命令,然後將輸出結果立刻代換到當前命令行中。例如定義一個變量存放date
命令的輸出:
$ DATE=`date` $ echo $DATE
命令代換也可以用$()
表示:
$ DATE=$(date)
用於算術計算,$(())
中的Shell變量取值將轉換成整數,例如:
$ VAR=45 $ echo $(($VAR+3))
$(())
中只能用+-*/和()運算符,並且只能做整數運算。
和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命令的輸出)
和C語言不一樣,Shell腳本中的單引號和雙引號一樣都是字符串的界定符(雙引號下一節介紹),而不是字符的界定符。單引號用於保持引號內所有字符的字面值,即使引號內的\和回車也不例外,但是字符串中不能出現單引號。如果引號沒有配對就輸入回車,Shell會給出續行提示符,要求用戶把引號配上對。例如:
$ echo '$SHELL' $SHELL $ echo 'ABC\(回車) > DE'(再按一次回車結束命令) ABC\ DE
雙引號用於保持引號內所有字符的字面值(回車也不例外),但以下情況除外:
-
$加變量名可以取變量的值
-
反引號仍表示命令替換
-
\$表示$的字面值
-
\`表示`的字面值
-
\"表示"的字面值
-
\\表示\的字面值
-
除以上情況之外,在其它字符前面的\無特殊含義,只表示字面值
$ 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
啓動時自動執行的腳本。用戶可以把一些環境變量的設置和alias
、umask
設置放在啓動腳本中,這樣每次啓動Shell時這些設置都自動生效。思考一下,bash
在執行啓動腳本時是以fork
子Shell方式執行的還是以source
方式執行的?
啓動bash的方法不同,執行啓動腳本的步驟也不相同,具體可分爲以下幾種情況。
4.1. 作爲交互登錄Shell啓動,或者使用--login參數啓動 請點評
交互Shell是指用戶在提示符下輸命令的Shell而非執行腳本的Shell,登錄Shell就是在輸入用戶名和密碼登錄後得到的Shell,比如從字符終端登錄或者用telnet
/ssh
從遠程登錄,但是從圖形界面的窗口管理器登錄之後會顯示桌面而不會產生登錄Shell(也不會執行啓動腳本),在圖形界面下打開終端窗口得到的Shell也不是登錄Shell。
這樣啓動bash
會自動執行以下腳本:
-
首先執行
/etc/profile
,系統中每個用戶登錄時都要執行這個腳本,如果系統管理員希望某個設置對所有用戶都生效,可以寫在這個腳本里 -
然後依次查找當前用戶主目錄的
~/.bash_profile
、~/.bash_login
和~/.profile
三個文件,找到第一個存在並且可讀的文件來執行,如果希望某個設置只對當前用戶生效,可以寫在這個腳本里,由於這個腳本在/etc/profile
之後執行,/etc/profile
設置的一些環境變量的值在這個腳本中可以修改,也就是說,當前用戶的設置可以覆蓋(Override)系統中全局的設置。~/.profile
這個啓動腳本是sh
規定的,bash
規定首先查找以~/.bash_
開頭的啓動腳本,如果沒有則執行~/.profile
,是爲了和sh
保持一致。 -
順便一提,在退出登錄時會執行
~/.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
命令啓動bash
,bash
將模擬sh
的行爲,以~/.bash_
開頭的那些啓動腳本就不認了。所以,如果作爲交互登錄Shell啓動,或者使用--login參數啓動,則依次執行以下腳本:
-
/etc/profile
-
~/.profile
如果作爲交互Shell啓動,相當於自動執行以下命令:
if [ -n "$ENV" ]; then . "$ENV"; fi
如果作爲非交互Shell啓動,則不執行任何啓動腳本。通常我們寫的Shell腳本都以#!/bin/sh
開頭,都屬於這種方式。
http://blog.163.com/bobile45@126/blog/static/9606199220126264495372/