簡(jiǎn)介
shell 是類 UNIX 系統(tǒng)的外殼,使用 shell 用于實(shí)現(xiàn)人機(jī)交互的目的,我們通過(guò)它可以與內(nèi)核之間進(jìn)行交互,從而輕松完成一些操作。換句話說(shuō),我們可以認(rèn)為 shell 就是一個(gè)人機(jī)交互方式,通過(guò)它,我們不需要有編程基礎(chǔ),不需要直接操作計(jì)算機(jī)內(nèi)核則可以完成一些想要的工作;事實(shí)上 shell 可以分為圖形化的 shell 和命令行 shell,我們用鼠標(biāo)操作桌面也是一個(gè)圖形化 shell 為我們提供了交互,這邊主要討論的是命令行 shell 的學(xué)習(xí)。
Shell有兩種執(zhí)行命令的方式:
- 交互式(Interactive):用戶在終端輸入一條命令,Shell就解釋執(zhí)行一條,并且可以直接顯示結(jié)果。
- 批處理(Batch):用戶事先寫一個(gè)Shell腳本(Script),其中有很多條命令,讓Shell一次把這些命令執(zhí)行完,而不必一條一條地敲命令,而由于 shell 本身就被看做是一種腳本語(yǔ)言,也有變量和流程控制語(yǔ)句,因此它具備的功能遠(yuǎn)比 windows 下的批處理要強(qiáng)大。
常用 shell
shell 本身是作為類 UNIX 系統(tǒng)的外殼,而它本身并不是唯一的,也就是說(shuō)當(dāng)你使用 linux 操作系統(tǒng)時(shí),你可以更換不同的 shell,常用的 shell 有: bash,zsh,dash,csh 等等。
bash
一般而言 MAC 電腦下默認(rèn)的 shell 為 bash,ubuntu 等系統(tǒng)登錄后,用戶的默認(rèn) shell 為 bash,內(nèi)部命令一共有40個(gè)。
dash
它比 Bash 小,只需要較少的磁盤空間,但是它的對(duì)話性功能也較少,而 ubuntu 等系統(tǒng)開啟加載的 shell 為 dash (據(jù)說(shuō)可以提高啟動(dòng)速度)。
csh
C shell 是一個(gè)交互式命令解釋器和一種命令編程語(yǔ)言,采用的語(yǔ)法類似于 C 編程語(yǔ)言,共有 52 個(gè)內(nèi)部命令。
zsh
zsh 原本是一個(gè) Linux 用戶很少使用的 shell,雖然它功能強(qiáng)大,但由于配置過(guò)于復(fù)雜,難以學(xué)習(xí),因此使用的人少,但這兩年由于 oh my zsh github 等一些社區(qū)的流行,讓 zsh 的使用越來(lái)越廣泛,由于它更加人性化,功能更加強(qiáng)大,也成為越來(lái)越多人 UNIX 下的默認(rèn) shell。
解釋型語(yǔ)言
傳統(tǒng)的程序設(shè)計(jì)語(yǔ)言,例如Fortran、Ada、Pascal、C、C++和Java,都是編譯型語(yǔ)言;而像 awk、Perl、Python、Ruby 與 Shell 等都屬于解釋型語(yǔ)言,即腳本語(yǔ)言。
兩者的區(qū)別是,編譯型語(yǔ)言需要一次性編譯成二進(jìn)制代碼,才可以被計(jì)算機(jī)執(zhí)行,之后都是執(zhí)行這個(gè)可執(zhí)行程序,無(wú)需再編譯因此執(zhí)行速度快;解釋型語(yǔ)言則是,解釋器(interpreter)需要讀取我們編寫的源代碼(source code),并將其轉(zhuǎn)換成目標(biāo)代碼(object code),再由計(jì)算機(jī)運(yùn)行,因?yàn)槊看螆?zhí)行程序都多了編譯的過(guò)程,因此效率有所下降。
shell 的適用場(chǎng)景
shell 腳本有著相當(dāng)好的移植性,經(jīng)過(guò) POSIX 標(biāo)準(zhǔn)化,shell 腳本幾乎可以在各種類 UNIX 操作系統(tǒng)上使用,并且最新的 windows 系統(tǒng)也將會(huì)加入 shell,也就是說(shuō),未來(lái),幾乎所有的 PC 都將支持 shell 腳本的使用。
shell 腳本開發(fā)較為簡(jiǎn)單,語(yǔ)法簡(jiǎn)單易學(xué),通過(guò)調(diào)用各種工具可以輕松的實(shí)現(xiàn)某個(gè)功能,相比于 C、C++ 等可以說(shuō)要簡(jiǎn)單的多。
shell 腳本同樣有它不完美之處,有效率低,功能受限等問(wèn)題,在如下情況下,一般不使用 shell:
- 資源密集型的任務(wù),尤其在需要考慮效率時(shí)(比如,排序,hash等等)。
- 需要處理大任務(wù)的數(shù)學(xué)操作,尤其是浮點(diǎn)運(yùn)算,精確運(yùn)算,或者復(fù)雜的算術(shù)運(yùn)算(這種情況一般使用C++或FORTRAN 來(lái)處理)。
- 有跨平臺(tái)(操作系統(tǒng))移植需求(一般使用C 或Java)。
- 復(fù)雜的應(yīng)用,在必須使用結(jié)構(gòu)化編程的時(shí)候(需要變量的類型檢查,函數(shù)原型,等等)。
- 對(duì)于影響系統(tǒng)全局性的關(guān)鍵任務(wù)應(yīng)用。
- 對(duì)于安全有很高要求的任務(wù),比如你需要一個(gè)健壯的系統(tǒng)來(lái)防止入侵、破解、惡意破壞等等。
- 項(xiàng)目由連串的依賴的各個(gè)部分組成。
- 需要大規(guī)模的文件操作。
- 需要多維數(shù)組的支持。
- 需要數(shù)據(jù)結(jié)構(gòu)的支持,比如鏈表或數(shù)等數(shù)據(jù)結(jié)構(gòu)。
- 需要產(chǎn)生或操作圖形化界面 GUI。
- 需要直接操作系統(tǒng)硬件。
- 需要 I/O 或socket 接口。
- 需要使用庫(kù)或者遺留下來(lái)的老代碼的接口。
- 私人的、閉源的應(yīng)用(shell 腳本把代碼就放在文本文件中,全世界- 都能看到)。
腳本執(zhí)行
加入解釋器說(shuō)明
首先新建一個(gè)文件,一般我們?nèi)∶麨?xxx.sh,.sh 為擴(kuò)展名,事實(shí)上你可以不加入這個(gè)擴(kuò)展名,但為了方便我們自己了解,一般建議還是加上 .sh。
第一行輸入 #!/bin/bash
,“#!” 是一個(gè)約定的標(biāo)記,它告訴系統(tǒng)這個(gè)腳本需要什么解釋器來(lái)執(zhí)行,即使用哪一種Shell。如果你使用 csh ,你則在第一行輸入 #!/bin/csh
。
如何運(yùn)行腳本
以這段腳本代碼為例,文件名為 tesh.sh:
#!/bin/bash
echo "Hello World !"
我們有三種方法執(zhí)行這段腳本。
- 終端輸入作為解釋器參數(shù):
bash test.sh
,注意這種方式運(yùn)行的腳本,不需要在第一行指定解釋器信息,因?yàn)椴粫?huì)起到任何效果,也就是說(shuō),你輸入bash test.sh
和dash test.sh
很可能會(huì)得到不同的結(jié)果。 - 作為可執(zhí)行程序:首先我們需要將文件變成可執(zhí)行程序,一般而言,linux 下除非二進(jìn)制可執(zhí)行程序(編譯生成的文件),一般的文本文件默認(rèn)都是不可執(zhí)行的,
chmod +x ./test.sh #使腳本具有執(zhí)行權(quán)限
,然后直接執(zhí)行該文件,./test.sh #執(zhí)行腳本
。注意,一定要寫成./test.sh
,而不是 test.sh。 -
source ./test.sh
使用 bash 的內(nèi)置命令來(lái)運(yùn)行腳本,source 可以用.
符號(hào)來(lái)代替。
source filename 與 sh filename 及 ./filename 執(zhí)行腳本的區(qū)別:
- 當(dāng)shell腳本具有可執(zhí)行權(quán)限時(shí),用 sh filename 與 ./filename 執(zhí)行腳本是沒有區(qū)別得。./filename 是因?yàn)楫?dāng)前目錄沒有在 PATH 中,所有"."是用來(lái)表示當(dāng)前目錄的。
- sh filename 重新建立一個(gè)子shell,在子 shell 中執(zhí)行腳本里面的語(yǔ)句,該子 shell 繼承父 shell 的環(huán)境變量,但子 shell 新建的、改變的變量不會(huì)被帶回父 shell,除非使用 export。
- source filename:這個(gè)命令其實(shí)只是簡(jiǎn)單地讀取腳本里面的語(yǔ)句依次在當(dāng)前 shell 里面執(zhí)行,沒有建立新的子 shell。那么腳本里面所有新建、改變變量的語(yǔ)句都會(huì)保存在當(dāng)前shell里面。
基礎(chǔ)語(yǔ)法
echo
echo是Shell的一個(gè)內(nèi)部指令,用于在屏幕上打印出指定的字符串。
直接輸出字符串:echo "hello world!"
輸出變量:
o="hello world!"
echo "the string is $o"
顯示結(jié)果重定向至文件:echo "It is a test" > myfile
printf
printf 命令用于格式化輸出, 是 echo 命令的增強(qiáng)版。它是 C 語(yǔ)言 printf() 庫(kù)函數(shù)的一個(gè)有限的變形,并且在語(yǔ)法上有些不同。注意:printf 由 POSIX 標(biāo)準(zhǔn)所定義,移植性要比 echo 好。
printf 命令的語(yǔ)法:printf format-string [arguments...] format-string 為格式控制字符串,arguments 為參數(shù)列表。shell 中 printf 功能和用法與 C 語(yǔ)言中的 printf 函數(shù)類似,這邊不再詳細(xì)說(shuō)明。
定義變量
變量直接采用賦值語(yǔ)句,類似 C 語(yǔ)言,但變量名和等號(hào)之間不能有空格,這可能和你熟悉的所有編程語(yǔ)言都不一樣,一旦加入空格,則會(huì)報(bào)錯(cuò)。
firstValue="hello"
變量名的命名須遵循如下規(guī)則:
- 首個(gè)字符必須為字母(a-z,A-Z)。
- 中間不能有空格,可以使用下劃線(_)。
- 不能使用標(biāo)點(diǎn)符號(hào)。
- 不能使用bash里的關(guān)鍵字(可用help命令查看保留關(guān)鍵字)。
使用變量
使用一個(gè)定義過(guò)的變量,只要在變量名前面加美元符號(hào)($)即可,如:
your_name="alading"
echo $your_name
echo ${your_name}
變量名外面的花括號(hào)是可選的,加不加都行,加花括號(hào)是為了幫助解釋器識(shí)別變量的邊界,如:echo "I am good at ${skill}Script"
推薦給所有變量加上花括號(hào),這是個(gè)好的 shell 編程習(xí)慣。
重新定義變量
已定義的變量,可以被重新定義,如:
your_name="alading"
echo ${your_name}
your_name="aladin"
echo ${your_name}
注意,第二次賦值的時(shí)候不能寫 $myUrl="adin",只有使用變量的時(shí)候才加美元符($)。
只讀變量
使用 readonly 命令可以將變量定義為只讀變量,只讀變量的值不能被改變。
#!/bin/bash
your_name="alading"
readonly your_name
your_name="aladin"
運(yùn)行腳本,結(jié)果如下:
/bin/sh: NAME: This variable is read only.
刪除變量
使用 unset 命令可以刪除變量。
#!/bin/bash
your_name="alading"
unset your_name
echo $your_name
特殊變量
這邊需要記住如下表格的內(nèi)容,shell 腳本會(huì)頻繁靈活的調(diào)用如下內(nèi)容。
變量 | 含義 |
---|---|
$0 | 當(dāng)前腳本的文件名 |
$n | 傳遞給腳本或函數(shù)的參數(shù)。n 是一個(gè)數(shù)字,表示第幾個(gè)參數(shù)。例如,第一個(gè)參數(shù)是$1,第二個(gè)參數(shù)是$2。 |
$# | 傳遞給腳本或函數(shù)的參數(shù)個(gè)數(shù)。 |
$* | 傳遞給腳本或函數(shù)的所有參數(shù)。 |
$@ | 傳遞給腳本或函數(shù)的所有參數(shù)。被雙引號(hào)(" ")包含時(shí),與 $* 稍有不同,下面將會(huì)講到。 |
$? | 上個(gè)命令的退出狀態(tài),或函數(shù)的返回值。 |
$$ | 當(dāng)前Shell進(jìn)程ID。對(duì)于 Shell 腳本,就是這些腳本所在的進(jìn)程ID。 |
#!/bin/bash
echo "$0 $1 $# $* $@ $? $$"
運(yùn)行結(jié)果:
$./test.sh haha
./test.sh haha 1 haha haha 0 14520
轉(zhuǎn)義字符
可以使用 echo 命令的 -e 進(jìn)行轉(zhuǎn)義,-E 選項(xiàng)禁止轉(zhuǎn)義,默認(rèn)情況,不進(jìn)行轉(zhuǎn)義。
轉(zhuǎn)義字符 | 含義 |
---|---|
\ | 反斜杠 |
\a | 警報(bào),響鈴 |
\b | 退格(刪除鍵) |
\f | 換頁(yè)(FF),將當(dāng)前位置移到下頁(yè)開頭 |
\n | 換行 |
\r | 回車 |
\t | 水平制表符(tab鍵) |
\v | 垂直制表符 |
echo -e "Value1 \n"
echo "Value2 \n"
運(yùn)行結(jié)果:
>> Value \n
>> Value2
命令替換
shell 中有許多內(nèi)置的軟件和命令,如: ls , pwd , date 等,我們可以在 shell 腳本中嵌入這些軟件運(yùn)行的結(jié)果。
#!/bin/bash
DATE=`date`
echo "Date is $DATE"
運(yùn)行結(jié)果
Sat Jun 17 15:19:56 CST 2017
變量替換
形式 | 說(shuō)明 |
---|---|
${var} | 變量本來(lái)的值 |
${var:-word} | 如果變量 var 為空或已被刪除(unset),那么返回 word,但不改變 var 的值。 |
${var:=word} | 如果變量 var 為空或已被刪除(unset),那么返回 word,并將 var 的值設(shè)置為 word。 |
${var:?message} | 如果變量 var 為空或已被刪除(unset),那么將消息 message 送到標(biāo)準(zhǔn)錯(cuò)誤輸出,可以用來(lái)檢測(cè)變量 var 是否可以被正常賦值。若此替換出現(xiàn)在Shell腳本中,那么腳本將停止運(yùn)行。 |
${var:+word} | 如果變量 var 被定義,那么返回 word,但不改變 var 的值。 |
減號(hào)“—”和加號(hào)“+”分別是當(dāng)變量無(wú)定義和有定義的時(shí)候返回Word,都不改變var;等于號(hào)“=”,不管有沒有定義,都給var重新賦值,并返回Word;對(duì)于問(wèn)號(hào)“?”,當(dāng)變量沒有定義的時(shí)候直接輸出message并且退出,當(dāng)變量有定義的時(shí)候,不執(zhí)行任何操作,相當(dāng)于直接跳過(guò)了。
字符串
字符串是shell編程中最常用最有用的數(shù)據(jù)類型(除了數(shù)字和字符串,也沒啥其它類型好用了),字符串可以用單引號(hào),也可以用雙引號(hào),也可以不用引號(hào)。
- 單引號(hào)里的任何字符都會(huì)原樣輸出,單引號(hào)字符串中的變量是無(wú)效的;
- 雙引號(hào)里可以有變量,雙引號(hào)里可以出現(xiàn)轉(zhuǎn)義字符
獲取字符串長(zhǎng)度:
${#parameter}
Parameter length. The length in characters of the value of parameter is substituted.
string="abcd"
echo ${#string} #輸出 4
提取子字符串:
string="alibaba is a great company"
echo ${string:1:4} #輸出liba
查找子字符串
string="alibaba is a great company"
echo `expr index "$string" is`
數(shù)組
bash支持一維數(shù)組(不支持多維數(shù)組),并且沒有限定數(shù)組的大小。類似與C語(yǔ)言,數(shù)組元素的下標(biāo)由0開始編號(hào)。獲取數(shù)組中的元素要利用下標(biāo),下標(biāo)可以是整數(shù)或算術(shù)表達(dá)式,其值應(yīng)大于或等于0。
用括號(hào)來(lái)表示數(shù)組,數(shù)組元素用“空格”符號(hào)分割開。定義數(shù)組的一般形式為:array_name=(value1 ... valuen)
array_name=(value0 value1 value2 value3)
或者
array_name=(
value0
value1
value2
value3
)
單獨(dú)賦值:
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
讀取數(shù)組元素值的一般格式是:${array_name[index]},同普通變量類似。
獲取數(shù)組的長(zhǎng)度:
# 取得數(shù)組元素的個(gè)數(shù)
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得數(shù)組單個(gè)元素的長(zhǎng)度
lengthn=${#array_name[n]}
運(yùn)算符
算術(shù)運(yùn)算符
算術(shù)運(yùn)算符基本上和 C 語(yǔ)言保持一致。
a=10
b=20
運(yùn)算符 | 說(shuō)明 | 舉例 |
---|---|---|
+ | 加法 |
expr $a + $b 結(jié)果為 30。 |
- | 減法 |
expr $a - $b 結(jié)果為 10。 |
* | 乘法 |
expr $a \* $b 結(jié)果為 200。 |
/ | 除法 |
expr $b / $a 結(jié)果為 2。 |
% | 取余 |
expr $b % $a 結(jié)果為 0。 |
= | 賦值 | a=$b 將把變量 b 的值賦給 a。 |
== | 相等。用于比較兩個(gè)數(shù)字,相同則返回 true。 | [ $a == $b ] 返回 false。 |
!= | 不相等。用于比較兩個(gè)數(shù)字,不相同則返回 true。 | [ $a != $b ] 返回 true。 |
關(guān)系運(yùn)算符
a=10
b=20
運(yùn)算符 | 說(shuō)明 | 舉例 |
---|---|---|
-eq | 檢測(cè)兩個(gè)數(shù)是否相等,相等返回 true。 | [ $a -eq $b ] 返回 true。 |
-ne | 檢測(cè)兩個(gè)數(shù)是否相等,不相等返回 true。 | [ $a -ne $b ] 返回 true。 |
-gt | 檢測(cè)左邊的數(shù)是否大于右邊的,如果是,則返回 true。 | [ $a -gt $b ] 返回 false。 |
-lt | 檢測(cè)左邊的數(shù)是否小于右邊的,如果是,則返回 true。 | [ $a -lt $b ] 返回 true。 |
-ge | 檢測(cè)左邊的數(shù)是否大等于右邊的,如果是,則返回 true。 | [ $a -ge $b ] 返回 false。 |
-le | 檢測(cè)左邊的數(shù)是否小于等于右邊的,如果是,則返回 true。 | [ $a -le $b ] 返回 true。 |
布爾運(yùn)算符
a=10
b=20
運(yùn)算符 | 說(shuō)明 | 舉例 |
---|---|---|
! | 非運(yùn)算,表達(dá)式為 true 則返回 false,否則返回 true。 | [ ! false ] 返回 true。 |
-o | 或運(yùn)算,有一個(gè)表達(dá)式為 true 則返回 true。 | [ $a -lt 20 -o $b -gt 100 ] 返回 true。 |
-a | 與運(yùn)算,兩個(gè)表達(dá)式都為 true 才返回 true。 | [ $a -lt 20 -a $b -gt 100 ] 返回 false。 |
字符串運(yùn)算符
a="abc"
b="efg"
運(yùn)算符 | 說(shuō)明 | 舉例 |
---|---|---|
= | 檢測(cè)兩個(gè)字符串是否相等,相等返回 true。 | [ $a = $b ] 返回 false。 |
!= | 檢測(cè)兩個(gè)字符串是否相等,不相等返回 true。 | [ $a != $b ] 返回 true。 |
-z | 檢測(cè)字符串長(zhǎng)度是否為0,為0返回 true。 | [ -z $a ] 返回 false。 |
-n | 檢測(cè)字符串長(zhǎng)度是否為0,不為0返回 true。 | [ -z $a ] 返回 true。 |
str | 檢測(cè)字符串是否為空,不為空返回 true。 | [ $a ] 返回 true。 |
文件測(cè)試運(yùn)算符
file="~/test.sh"
操作符 | 說(shuō)明 | 舉例 |
---|---|---|
-b file | 檢測(cè)文件是否是塊設(shè)備文件,如果是,則返回 true。 | [ -b $file ] 返回 false。 |
-c file | 檢測(cè)文件是否是字符設(shè)備文件,如果是,則返回 true。 | [ -b $file ] 返回 false。 |
-d file | 檢測(cè)文件是否是目錄,如果是,則返回 true。 | [ -d $file ] 返回 false。 |
-f file | 檢測(cè)文件是否是普通文件(既不是目錄,也不是設(shè)備文件),如果是,則返回 true。 | [ -f $file ] 返回 true。 |
-g file | 檢測(cè)文件是否設(shè)置了 SGID 位,如果是,則返回 true。 | [ -g $file ] 返回 false。 |
-k file | 檢測(cè)文件是否設(shè)置了粘著位(Sticky Bit),如果是,則返回 true。 [ -k $file ] 返回 false。 | |
-p file | 檢測(cè)文件是否是具名管道,如果是,則返回 true。 | [ -p $file ] 返回 false。 |
-u file | 檢測(cè)文件是否設(shè)置了 SUID 位,如果是,則返回 true。 | [ -u $file ] 返回 false。 |
-r file | 檢測(cè)文件是否可讀,如果是,則返回 true。 | [ -r $file ] 返回 true。 |
-w file | 檢測(cè)文件是否可寫,如果是,則返回 true。 | [ -w $file ] 返回 true。 |
-x file | 檢測(cè)文件是否可執(zhí)行,如果是,則返回 true。 | [ -x $file ] 返回 true。 |
-s file | 檢測(cè)文件是否為空(文件大小是否大于0),不為空返回 true。 | [ -s $file ] 返回 true。 |
-e file | 檢測(cè)文件(包括目錄)是否存在,如果是,則返回 true。 | [ -e $file ] 返回 true。 |
注釋
以“#”開頭的行就是注釋,會(huì)被解釋器忽略,sh 里沒有多行注釋,只能每一行加一個(gè) # 號(hào)。
在開發(fā)過(guò)程中,遇到大段的代碼需要臨時(shí)注釋起來(lái),過(guò)一會(huì)兒又取消注釋,怎么辦呢?每一行加個(gè)#符號(hào)太費(fèi)力了,可以把這一段要注釋的代碼用一對(duì)花括號(hào)括起來(lái),定義成一個(gè)函數(shù),沒有地方調(diào)用這個(gè)函數(shù),這塊代碼就不會(huì)執(zhí)行,達(dá)到了和注釋一樣的效果。
語(yǔ)句
判斷語(yǔ)句
if ... else 語(yǔ)句的語(yǔ)法:
if [ expression ]
then
Statement(s) to be executed if expression is true
fi
expression 和方括號(hào)([ ])之間必須有空格,條件語(yǔ)句的主體內(nèi)容前面必須有 tab 間隔,否則會(huì)有語(yǔ)法錯(cuò)誤。
#!/bin/sh
a=10
b=20
if [ $a != $b ]
then
echo "a is not equal to b"
fi
運(yùn)行結(jié)果:
a is not equal to b
if ... else ... fi 語(yǔ)句的語(yǔ)法:
if [ expression ]
then
Statement(s) to be executed if expression is true
else
Statement(s) to be executed if expression is not true
fi
if ... elif ... fi 語(yǔ)句的語(yǔ)法為:
if [ expression 1 ]
then
Statement(s) to be executed if expression 1 is true
elif [ expression 2 ]
then
Statement(s) to be executed if expression 2 is true
elif [ expression 3 ]
then
Statement(s) to be executed if expression 3 is true
else
Statement(s) to be executed if no expression is true
fi
測(cè)試語(yǔ)句
Shell中的 test 命令用于檢查某個(gè)條件是否成立,它可以進(jìn)行數(shù)值、字符和文件三個(gè)方面的測(cè)試,例如:
num1=100
num2=100
if test $[num1] -eq $[num2]
then
echo 'The two numbers are equal!'
else
echo 'The two numbers are not equal!'
fi
結(jié)果:
The two numbers are equal!
test 的表述方法一般都可以直接用 if 來(lái)完成,這邊只做個(gè)介紹,不推薦使用。
case
case ... esac 與其他語(yǔ)言中的 switch ... case 語(yǔ)句類似,是一種多分枝選擇結(jié)構(gòu)。case 語(yǔ)句匹配一個(gè)值或一個(gè)模式,如果匹配成功,執(zhí)行相匹配的命令。case語(yǔ)句格式如下:
case 值 in
模式1)
command1
command2
command3
;;
模式2)
command1
command2
command3
;;
*)
command1
command2
command3
;;
esac
舉例:
echo 'Input a number between 1 to 4'
echo 'Your number is:\c'
read aNum
case $aNum in
1) echo 'You select 1'
;;
2) echo 'You select 2'
;;
3) echo 'You select 3'
;;
4) echo 'You select 4'
;;
*) echo 'You do not select a number between 1 to 4'
;;
esac
輸入不同的內(nèi)容,會(huì)有不同的結(jié)果,例如:
Input a number between 1 to 4
Your number is:3
You select 3
for循環(huán)
與其他編程語(yǔ)言類似,Shell支持for循環(huán)。for循環(huán)一般格式為:
for 變量 in 列表
do
command1
command2
...
commandN
done
列表是一組值(數(shù)字、字符串等)組成的序列,每個(gè)值通過(guò)空格分隔。每循環(huán)一次,就將列表中的下一個(gè)值賦給變量。in 列表是可選的,如果不用它,for 循環(huán)使用命令行的位置參數(shù)。for 循環(huán)在使用過(guò)程中相當(dāng)方便,可以將任意內(nèi)容作為 in 的目標(biāo),然后可以快速的檢索執(zhí)行相關(guān)內(nèi)容。例如,我們需要將 windows 下壓縮的所有文件夾在 linux 下解壓,則可以用 for 語(yǔ)句將文件以 gb2312 的模式解壓,具體代碼如下:
#!/bin/bash
for i in *.zip
do
unzip -O Gb2312 "$i"
done
while 語(yǔ)句
while循環(huán)用于不斷執(zhí)行一系列命令,也用于從輸入文件中讀取數(shù)據(jù);命令通常為測(cè)試條件。其格式為:
while command
do
Statement(s) to be executed if command is true
done
while循環(huán)可用于讀取鍵盤信息。下面的例子中,輸入信息被設(shè)置為變量FILM,按<Ctrl-D>結(jié)束循環(huán)。
echo 'type <CTRL-D> to terminate'
echo -n 'enter your most liked film: '
while read FILM
do
echo "Yeah! great film the $FILM"
done
until 語(yǔ)句
until 循環(huán)與 while 循環(huán)在處理方式上剛好相反,until 循環(huán)執(zhí)行一系列命令直至條件為 true 時(shí)停止。
until 循環(huán)格式為:
until command
do
Statement(s) to be executed until command is true
done
例如,使用 until 命令輸出 0 ~ 9 的數(shù)字:
#!/bin/bash
a=0
until [ ! $a -lt 10 ]
do
echo $a
a=`expr $a + 1`
done
break 語(yǔ)句
在循環(huán)過(guò)程中,有時(shí)候需要在未達(dá)到循環(huán)結(jié)束條件時(shí)強(qiáng)制跳出循環(huán),像大多數(shù)編程語(yǔ)言一樣,Shell也使用 break 和 continue 來(lái)跳出循環(huán)。
continue命令
continue 命令與 break 命令類似,只有一點(diǎn)差別,它不會(huì)跳出所有循環(huán),僅僅跳出當(dāng)前循環(huán)。
函數(shù)
函數(shù)可以讓我們將一個(gè)復(fù)雜功能劃分成若干模塊,讓程序結(jié)構(gòu)更加清晰,代碼重復(fù)利用率更高,Shell 函數(shù)也必須先定義后使用。
Shell 函數(shù)的定義格式如下:
function function_name () {
list of commands
[ return value ]
}
function 關(guān)鍵字可加可不加;函數(shù)返回值,可以顯式增加return語(yǔ)句;如果不加,會(huì)將最后一條命令運(yùn)行結(jié)果作為返回值。
#!/bin/bash
funWithReturn(){
echo "The function is to get the sum of two numbers..."
echo -n "Input first number: "
read aNum
echo -n "Input another number: "
read anotherNum
echo "The two numbers are $aNum and $anotherNum !"
return $(($aNum+$anotherNum))
}
funWithReturn
# Capture value returnd by last command
ret=$?
echo "The sum of two numbers is $ret !"
運(yùn)行結(jié)果:
The function is to get the sum of two numbers...
Input first number: 25
Input another number: 50
The two numbers are 25 and 50 !
The sum of two numbers is 75 !
函數(shù)返回值在調(diào)用該函數(shù)后通過(guò) $? 來(lái)獲得,不像 C 語(yǔ)言的直接調(diào)用賦值。
在Shell中,調(diào)用函數(shù)時(shí)可以向其傳遞參數(shù)。在函數(shù)體內(nèi)部,通過(guò) $n 的形式來(lái)獲取參數(shù)的值,例如,$1表示第一個(gè)參數(shù),$2表示第二個(gè)參數(shù)...
#!/bin/bash
funWithParam(){
echo "The value of the first parameter is $1 !"
echo "The value of the second parameter is $2 !"
echo "The value of the tenth parameter is $10 !"
echo "The value of the tenth parameter is ${10} !"
echo "The value of the eleventh parameter is ${11} !"
echo "The amount of the parameters is $# !" # 參數(shù)個(gè)數(shù)
echo "The string of the parameters is $* !" # 傳遞給函數(shù)的所有參數(shù)
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73
運(yùn)行結(jié)果:
The value of the first parameter is 1 !
The value of the second parameter is 2 !
The value of the tenth parameter is 10 !
The value of the tenth parameter is 34 !
The value of the eleventh parameter is 73 !
The amount of the parameters is 12 !
The string of the parameters is 1 2 3 4 5 6 7 8 9 34 73 !"
注意:$10 不能獲取第十個(gè)參數(shù),獲取第十個(gè)參數(shù)需要${10}。當(dāng) n>=10 時(shí),需要使用${n}來(lái)獲取參數(shù),所以一般良好的方式是所有的變量參數(shù)調(diào)用時(shí)都加上 {}
。
重定向
輸出重定向
命令的輸出不僅可以是顯示器,還可以很容易的轉(zhuǎn)移向到文件,這被稱為輸出重定向。上面我們?cè)谑褂?echo 的時(shí)候其實(shí)已經(jīng)用到了輸出重定向,這是 shell 下記錄日志的常用方法。
命令輸出重定向的語(yǔ)法為:
-
command > file
: 表示創(chuàng)建 file 文件,將 command 的結(jié)果輸出到 file 文件中,如果已經(jīng)存在 file 文件,則直接覆蓋源文件內(nèi)容。 -
command >> file
: 表示創(chuàng)建 file 文件,將 command 的結(jié)果輸出到 file 文件中,如果已經(jīng)存在 file 文件,則不覆蓋原文內(nèi)容,而在文件末尾進(jìn)行追加。
輸入重定向
和輸出重定向一樣,shell 命令也可以從文件獲取輸入,語(yǔ)法為:command < file
,這樣,本來(lái)需要從鍵盤獲取輸入的命令會(huì)轉(zhuǎn)移到文件讀取內(nèi)容。
輸入重定向到 users 文件,即:讀取 user 文件下的內(nèi)容,用 command 對(duì)這個(gè)文件內(nèi)容進(jìn)行處理。例如:wc -l < users
。
標(biāo)準(zhǔn)錯(cuò)誤文件
一般情況下,每個(gè) Unix/Linux 命令運(yùn)行時(shí)都會(huì)打開三個(gè)文件:
- 標(biāo)準(zhǔn)輸入文件(stdin):stdin的文件描述符為0,Unix程序默認(rèn)從stdin讀取數(shù)據(jù)。默認(rèn)情況下,command > file 將 stdout 重定向到 file
- 標(biāo)準(zhǔn)輸出文件(stdout):stdout 的文件描述符為1,Unix程序默認(rèn)向stdout輸出數(shù)據(jù)。command < file 將 stdin 重定向到 file。
- 標(biāo)準(zhǔn)錯(cuò)誤文件(stderr):stderr的文件描述符為2,Unix程序會(huì)向stderr流中寫入錯(cuò)誤信息。command 2 > file,stderr 重定向到 file。
一般我們可以這樣操作,將 stdout 和 stderr 分別重定向到 file:command >> file1 2 >> file2
/dev/null 文件
如果希望執(zhí)行某個(gè)命令,但又不希望在屏幕上顯示輸出結(jié)果,那么可以將輸出重定向到 /dev/null
,command > /dev/null 2>&1
可以用來(lái)屏蔽 stdout 和 stderr。
本文是一個(gè) bash 入門的基礎(chǔ)語(yǔ)法筆記,主要參考學(xué)習(xí)和整理了如下鏈接的內(nèi)容。
參考鏈接:
http://c.biancheng.net/cpp/shell/
http://blog.csdn.net/wangyangkobe/article/details/6595143
https://zhidao.baidu.com/question/489742760031792892.html
http://blog.csdn.net/hansel/article/details/9817129
http://www.360doc.com/content/13/1211/14/14541491_336331604.shtml