5/33 bash腳本基礎(chǔ)學(xué)習(xí)

簡(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.shdash 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/nullcommand > /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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • linux資料總章2.1 1.0寫的不好抱歉 但是2.0已經(jīng)改了很多 但是錯(cuò)誤還是無(wú)法避免 以后資料會(huì)慢慢更新 大...
    數(shù)據(jù)革命閱讀 12,237評(píng)論 2 33
  • Ubuntu的發(fā)音 Ubuntu,源于非洲祖魯人和科薩人的語(yǔ)言,發(fā)作 oo-boon-too 的音。了解發(fā)音是有意...
    螢火蟲de夢(mèng)閱讀 99,584評(píng)論 9 467
  • 這是我第一次嘗試使用雙拼輸入法翻譯一篇日本的Liunx基礎(chǔ)教材上的一章。共花費(fèi)一周左右。 shell的使用 前言 ...
    今後次閱讀 1,061評(píng)論 0 4
  • 漸漸發(fā)現(xiàn) 熬夜的你 其實(shí)很困,只是心里都有所牽掛 有所期待 遲遲讓你生怕錯(cuò)過(guò)下一秒的驚喜 。也許是我孤獨(dú)慣了,幸福...
    Paseo1376閱讀 800評(píng)論 0 1
  • 早上夢(mèng)到香格里拉的小伙伴們了,故意忘記一般,模糊了內(nèi)容,只記得我在跟暖男發(fā)消息,小志跟我說(shuō):沒關(guān)系,暖男看到了就會(huì)...
    維酥德瓦閱讀 461評(píng)論 1 0