1、
Shell腳本中用
#
表示注釋,相當于C語言的
//
注釋。但如果
#
位于第一行開頭,并且是
#!
(稱為Shebang
)則例外,它表示該腳本使用?后面指定的解釋器
/bin/sh
解釋執行
?
$ chmod +x script.sh $ ./script.sh
?
2、兩種執行Shell腳本的方法:
$ ./script.sh $ sh ./script.sh
3、 一行中可以輸入由分號;隔開的多個命令
?
$ cd ..;ls -l
4、
只存在于當前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變量不需要先定義后使用,如果對一個沒有定義的變量取值,則值為空字符串。
5、Shell腳本中的單引號和雙引號一樣都是字符串的界定符(雙引號下一節介紹),而不是字符的界定符。單引號用于保持引號內所有字符的字面值,即使引號內的\和回車也不例外,但是字符串中不能出現單引號。如果引號沒有配對就輸入回車,Shell會給出續行提示符,要求用戶把引號配上對。例如:
$ echo '$SHELL' $SHELL $ echo 'ABC\(回車) > DE'(再按一次回車結束命令) ABC\ DE
6、 命令代換:`或 $()
由反引號括起來的也是一條命令,Shell先執行該命令,然后將輸出結果立刻代換到當前命令行中。例如定義一個變量存放
date
命令的輸出:
$ DATE=`date` $ echo $DATE
命令代換也可以用
$()
表示:
$ DATE=$(date)
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 "\\" \
8、
啟動
bash
會自動執行以下腳本:
-
首先執行
/etc/profile
,系統中每個用戶登錄時都要執行這個腳本,如果系統管理員希望某個設置對所有用戶都生效,可以寫在這個腳本里 -
然后依次查找當前用戶主目錄的
~/.bash_profile
、~/.bash_login
和~/.profile
三個文件,找到第一個存在并且可讀的文件來執行,如果希望某個設置只對當前用戶生效,可以寫在這個腳本里,由于這個腳本在/etc/profile
之后執行,/etc/profile
設置的一些環境變量的值在這個腳本中可以修改,也就是說,當前用戶的設置可以覆蓋(Override) 系統中全局的設置。~/.profile
這個啟動腳本是sh
規定的,bash
規定首先查找以~/.bash_
開頭的啟動腳本,如果沒有則執行~/.profile
,是為了和sh
保持一致。 -
順便一提,在退出登錄時會執行
~/.bash_logout
腳本(如果它存在的話)。
?
9、條件測試test
?
命令
test
或
[
可以測試一個條件是否成立,如果測試結果為真,則該命令的Exit Status為0,如果測試結果為假,則命令的Exit Status為1(注意與C語言的邏輯表示正好相反)。例如測試兩個數的大小關系:
$ VAR=2 $ test $VAR -gt 1 $ echo $? 0 $ test $VAR -gt 3 $ echo $? 1 $ [ $VAR -gt 3 ] $ echo $? 1
雖然看起來很奇怪,但左方括號
[
確實是一個命令的名字,傳給命令的各參數之間應該用空格隔開
,比如,
$VAR
、
-gt
、
3
、
]
是
[
命令的四個參數,它們之間必須用空格隔開。命令
test
或
[
的參數形式是相同的,只不過
test
命令不需要
]
參數。以
[
命令為例,常見的測試命令如下表所示:
[ -d DIR ]
|
如果
DIR
存在并且是一個目錄則為真
|
[ -f FILE ]
|
如果
FILE
存在且是一個普通文件則為真
|
[ -z STRING ]
|
如果
STRING
的長度為零則為真
|
[ -n STRING ]
|
如果
STRING
的長度非零則為真
|
[ STRING1 = STRING2 ]
|
如果兩個字符串相同則為真 |
[ STRING1 != STRING2 ]
|
如果字符串不相同則為真 |
[ ARG1 OP ARG2 ]
|
ARG1
和
ARG2
應該是整數或者取值為整數的變量,
OP
是
-eq
(等于)
-ne
(不等于)
-lt
(小于)
-le
(小于等于)
-gt
(大于)
-ge
(大于等于)之中的一個
|
?
和C語言類似,測試條件之間還可以做與、或、非邏輯運算:
帶與、或、非的測試命令
[ ! EXPR ]
|
EXPR
可以是上表中的任意一種測試條件,!表示邏輯反
|
[ EXPR1 -a EXPR2 ]
|
EXPR1
和
EXPR2
可以是上表中的任意一種測試條件,
-a
表示邏輯與
|
[ EXPR1 -o EXPR2 ]
|
EXPR1
和
EXPR2
可以是上表中的任意一種測試條件,
-o
表示邏輯或
|
?
例如:
$ VAR=abc $ [ -d Desktop -a $VAR = 'abc' ] $ echo $? 0
注意,如果上例中的
$VAR
變量事先沒有定義,則被Shell展開為空字符串,會造成測試條件的語法錯誤(展開為
[ -d Desktop -a = 'abc' ]
),作為一種好的Shell編程習慣,應該總是把變量取值放在雙引號之中(展開為
[ -d Desktop -a "" = 'abc' ]
):
$ unset VAR $ [ -d Desktop -a $VAR = 'abc' ] bash: [: too many arguments $ [ -d Desktop -a "$VAR" = 'abc' ] $ echo $? 1
10、 case/esac
case
命令可類比C語言的
switch
/
case
語句,
esac
表示
case
語句塊的結束。C語言的
case
只能匹配整型或字符型常量表達式,而Shell腳本的
case
可以匹配字符串和Wildcard,每個匹配分支可以有若干條命令,末尾必須以;;結束,執行時找到第一個匹配的分支并執行相應的命令,然后直接跳到
esac
之后,不需要像C語言一樣用
break
跳出。
#! /bin/sh echo "Is it morning? Please answer yes or no." read YES_OR_NO case "$YES_OR_NO" in yes|y|Yes|YES) echo "Good Morning!";; [nN]*) echo "Good Afternoon!";; *) echo "Sorry, $YES_OR_NO not recognized. Enter yes or no." exit 1;; esac exit 0
使用
case
語句的例子可以在系統服務的腳本目錄
/etc/init.d
中找到。這個目錄下的腳本大多具有這種形式(以
/etc/apache2
為例):
case $1 in start) ... ;; stop) ... ;; reload | force-reload) ... ;; restart) ... *) log_success_msg "Usage: /etc/init.d/apache2 {start|stop|restart|reload|force-reload|start-htcacheclean|stop-htcacheclean}" exit 1 ;; esac
啟動
apache2
服務的命令是
$ sudo /etc/init.d/apache2 start
$1
是一個特殊變量,在執行腳本時自動取值為第一個命令行參數,也就是
start
,所以進入
start)
分支執行相關的命令。同理,命令行參數指定為
stop
、
reload
或
restart
可以進入其它分支執行停止服務、重新加載配置文件或重新啟動服務的相關命令。
11、if fi
和C語言類似,在Shell中用
if
、
then
、
elif
、
else
、
fi
這幾條命令實現分支控制。這種流程控制語句本質上也是由若干條Shell命令組成的,例如先前講過的
if [ -f ~/.bashrc ]; then . ~/.bashrc fi
其實是三條命令,
if [ -f ~/.bashrc ]
是第一條,
then . ~/.bashrc
是第二條,
fi
是第三條。如果兩條命令寫在同一行則需要用;號隔開,一行只寫一條命令就不需要寫;號了,另外,
then
后面有換行,但這條命令沒寫完,Shell會自動續行,把下一行接在
then
后面當作一條命令處理。和
[
命令一樣,要注意命令和各參數之間必須用空格隔開。
if
命令的參數組成一條子命令,如果該子命令的Exit Status為0(表示真),則執行
then
后面的子命令,如果Exit Status非0(表示假),則執行
elif
、
else
或者
fi
后面的子命令。
if
后面的子命令通常是測試命令,但也可以是其它命令。Shell腳本沒有{}括號,所以用
fi
表示
if
語句塊的結束。見下例:
#! /bin/sh if [ -f /bin/bash ] then echo "/bin/bash is a file" else echo "/bin/bash is NOT a file" fi if :; then echo "always true"; fi
:
是一個特殊的命令,稱為空命令,該命令不做任何事,但Exit Status總是真。此外,也可以執行
/bin/true
或
/bin/false
得到真或假的Exit Status。再看一個例子:
#! /bin/sh echo "Is it morning? Please answer yes or no." read YES_OR_NO if [ "$YES_OR_NO" = "yes" ]; then echo "Good morning!" elif [ "$YES_OR_NO" = "no" ]; then echo "Good afternoon!" else echo "Sorry, $YES_OR_NO not recognized. Enter yes or no." exit 1 fi exit 0
上例中的
read
命令的作用是等待用戶輸入一行字符串,將該字符串存到一個Shell變量中。
此外,Shell還提供了&&和||語法,和C語言類似,具有Short-circuit特性,很多Shell腳本喜歡寫成這樣:
test "$(whoami)" != 'root' && (echo you are using a non-privileged account; exit 1)
&&相當于“
if...then...
”,而||相當于“
if not...then...
”。&&和||用于連接兩個命令,而上面講的
-a
和
-o
僅用于在測試表達式中連接兩個測試條件,要注意它們的區別,例如,
test "$VAR" -gt 1 -a "$VAR" -lt 3
和以下寫法是等價的
test "$VAR" -gt 1 && test "$VAR" -lt 3
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
