在上一篇文章《不過時(shí)的技術(shù)-Bash腳本》中,我們簡(jiǎn)單介紹了Bash腳本,并且學(xué)會(huì)如何編寫、運(yùn)行一個(gè)Bash腳本。這篇文章我們將目光轉(zhuǎn)向Bash腳本的一些基礎(chǔ)知識(shí):
- 如何定義、使用變量
- export和source
- 特殊字符及轉(zhuǎn)義
- 腳本參數(shù)
- 命令替換
- 字符串驗(yàn)證
- Here文檔
變量
有三種方式定義變量:
- 在命令行或腳本中直接顯式定義
COLOR=red
千萬(wàn)不要像其他編程語(yǔ)言一樣在變量和=之間加空格!?。?/strong> - 使用
read命令從標(biāo)準(zhǔn)輸入給變量賦值
read COLOR - 第三種變量比較特殊,由參數(shù)直接傳入:
$0、$1、$2……其中$0為腳本名,$1是第一個(gè)參數(shù),以此類推。
在變量名前加$符引用變量,比如$COLOR。下面這段腳本讓用戶輸入進(jìn)程名,保存到一個(gè)變量里,然后查找相關(guān)進(jìn)程并殺掉。
#!/bin/sh
# Ask what to stop using the kill command and then kill it
echo which process do you want to kill?
read TOKILL
kill $(ps aux | grep $TOKILL | grep -v grep | awk '{print $2}')
這個(gè)腳本的最后一句看起來(lái)有點(diǎn)復(fù)雜,用到了命令替換、管道、awk等知識(shí)。如果你是那種不怕麻煩的人,可在命令行中一點(diǎn)一點(diǎn)去執(zhí)行,看看發(fā)生了什么:比如ps aux返回當(dāng)前進(jìn)程,ps aux | grep http在當(dāng)前進(jìn)程中找出http相關(guān)進(jìn)程,以此類推……事實(shí)上這是編寫腳本時(shí)常用的方法,先在命令行中一部分一部分實(shí)驗(yàn),成功后再組織成一段腳本。
如果執(zhí)行腳本時(shí)出錯(cuò)怎么辦?比如上面這段腳本運(yùn)行第二次時(shí),如果輸入的值一樣,就會(huì)報(bào)錯(cuò)。此時(shí)運(yùn)行bash -x tokill.sh可以打印出詳細(xì)的診斷信息:
foo:bin muxi$ bash -x tokill.sh
+ echo which process do you want to 'kill?'
which process do you want to kill?
+ read TOKILL
http
++ ps aux
++ grep -v grep
++ grep http
++ awk '{print $2}'
+ kill
kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
相信你已經(jīng)看出了問題所在,最后一步kill進(jìn)程時(shí)傳入的參數(shù)不對(duì)(為空)。這點(diǎn)不難想象,因?yàn)槲覀円呀?jīng)在上一次運(yùn)行時(shí)殺掉所有相關(guān)進(jìn)程了。
需要注意的是變量只在定義它的腳本中起效,如果在當(dāng)前腳本中進(jìn)入子腳本,那么該變量在子腳本中就不存在了。這點(diǎn)可以在命令行中得到驗(yàn)證:
foo:bin muxi$ COLOR=red
foo:bin muxi$ echo $COLOR
red
foo:bin muxi$ bash
bash-3.2$ echo $COLOR
bash-3.2$ COLOR=green
bash-3.2$ echo $COLOR
green
bash-3.2$ exit
exit
foo:bin muxi$ echo $COLOR
red
細(xì)心的讀者可能會(huì)注意到,定義變量時(shí)我一直用的大寫,這是一個(gè)好的編程習(xí)慣,人家一看就知道這是個(gè)變量。
export 和 source
如果想使用父腳本中定義的變量該怎么辦?答案是使用export將變量導(dǎo)入子腳本:
foo:bin muxi$ export COLOR=red
foo:bin muxi$ echo $COLOR
red
foo:bin muxi$ bash
bash-3.2$ echo $COLOR
red
source更厲害,它能將一個(gè)腳本中的所有內(nèi)容導(dǎo)入到另外一個(gè)腳本中。
#!/bin/sh
. ./slave.sh
echo the value of variable '$COLOR' is $COLOR
exit 0
#!/bin/sh
COLOR=yellow
source的厲害之處在于它能將變的東西和不變的東西分離開,聽著是不是很熟悉?這是計(jì)算機(jī)世界里一個(gè)基本的原則之一。以后大家會(huì)經(jīng)常在腳本中看到export和source。
特殊字符和轉(zhuǎn)義
在Shell腳本中,很多字符有特殊的含義:~代表當(dāng)前用戶主目錄, #注釋等,更多內(nèi)容可參考特殊字符列表。比如下面這段腳本,你覺得輸出會(huì)是什么?
echo 2 * 3 > 5
上面的腳本什么也沒輸出,它將一段文本重定向到文件5中。為了輸出2 * 3 > 5,需要這樣:echo '2 * 3 > 5'
腳本參數(shù)
執(zhí)行腳本時(shí)可傳入?yún)?shù),在腳本中使用$0, $1, $2……${10}, ${11}……引用參數(shù),其中$0代表腳本名。還有三個(gè)特殊變量:$#表示傳入?yún)?shù)個(gè)數(shù),$@返回所有參數(shù)列表,$*將所有參數(shù)以一個(gè)字符串的形式返回。下面這段程序用來(lái)遍歷參數(shù)列表,你能猜出為什么"$@"要加雙引號(hào)嗎?
for i in "$@"
do
echo $i
done
命令替換
編寫腳本時(shí),經(jīng)常一個(gè)命令需要使用另一個(gè)命令執(zhí)行完成后的結(jié)果,此時(shí)就用到了命令替換,比如ls -l $(which passwd)列出了passwd命令的文件屬性。
字符串驗(yàn)證
test -z $1 && exit 1 #如果第一個(gè)參數(shù)為空,返回狀態(tài)1退出
[[ $1=='[a-z]*' ]] || echo $1 does not start with a letter
恐怖的空格!??!$1之前必須有空格,之后必須沒空格?。?!
Here文檔
wall <<End-of-message
----------------------------
This is line 1 of the message.
This is line 2 of the message.
This is the last line of the message.
------------------------------
End-of-message
#!/bin/bash
# example of a scripted FTP session
lftp localhost <<EndOfSession
ls
get hosts
bye
EndOfSession
echo the file is now downloaded