前言:
問題一:什麼是shell?
答:從程序員的角度來看, Shell本身是一種用C語言編寫的程序,從用戶的角度來看,Shell是用戶與Linux操作系統溝通的橋樑。用戶既可以輸入命令執行,又可以利用 Shell腳本編程,完成更加複雜的操作。在Linux GUI日益完善的今天,在系統管理等領域,Shell編程仍然起着不可忽視的作用。深入地瞭解和熟練地掌握Shell編程,是每一個Linux用戶的必修功課之一。
目前最流行的Shell稱爲bash Shell,bash Shell腳本編程以其簡潔、高效而著稱,多年來成爲Linux程序員和系統管理員解決實際問題的利器。
問題二、爲什麼要使用shell腳本?
答:使用腳本編程語言的好處是,它們多半運行在比編譯型語言還高的層級,能夠輕易處理文件與目錄之類的對象。之所以要使用shell腳本是基於:
簡單性:shell是一個高級語言,通過它,你可以簡潔地表達複雜的操作。
可移植性:使用POSIX所定義的功能,可以做到腳本無須修改就可以在不同的系統上執行。
開發容易:可以在短時間內完成一個功能強大有好用的腳本。
一、初識shell腳本編程
利用vim文本編輯器編寫Shell腳本的格式是固定的,如下:
#!/bin/bash
#This is a shell file
echo "Hello World!"
第一行一定要使用#!指明系統需要哪種shell解釋用戶的shell程序,如:#!/bin/sh,#!/bin/bash,#!/bin/csh,#!/bin/tcsh和#!/bin/ksh等。如果首行沒有這句話,在執行腳本文件的時候,將會出現錯誤。
除首行外,以#開頭的行就是註釋行。
後續的部分就是主程序,Shell腳本像高級語言一樣,也有變量賦值,也有控制語句。
通常shell腳本多以.sh爲後綴。
執行shell的方式有兩種:第一種是爲shell腳本加上可執行權限並執行,第二種是通過bash命令執行shell腳本。
二、shell的基本語法知識
1、變量類別
(1)本地變量:只對當前shell進程有效的變量;對其它shell進程無效,包當前shell進程的子進程;
VAR_NAME=VALUE
變量賦值:向變量的存儲空間保存數據
變量引用:${VAR_NAME}
"":弱引用,裏面的變量會被替換;
'':強引用,裏面的所有字符都是字面量,直接輸出;
(2)環境變量:對當前shell進程及其子shell有效,對其它的shell進程無效;
定義:export VAR_NAME=VALUE
導出:export VAR_NAME
(當定義了一個本地變量,要在當前shell的子shell進程中使用,可用導出: export VAR_NAME)
撤消變量:unset VAR_NAME(可撤銷本地變量和環境變量)
設置只讀變量:readonly VAR_NAME(標誌變量爲不可改變的,即只讀變量)
(3)局部變量:對shell腳本中某代碼片斷有效;通常用於函數本地;
local VAR_NAME=VALUE(當函數調用結束,局部變量會隨之消失。也能用unset 撤銷局部變量。)
(4)位置變量:
$1, $2, ..., ${10}(當兩位數或超過兩位數時,最好用{}括起來)
(5)特殊變量:
$#: 傳遞到腳本的參數個數
$*: 以一個單字符串顯示所有向腳本傳遞的參數
$$: 腳本運行的當前進程ID號
$!: 後臺運行的最後一個進程的進程ID號
$@: 與$*相同,但是使用時加引號,並在引號中返回每個參數
$-: 顯示shell使用的當前選項,與set命令功能相同
$?: 顯示最後命令的退出狀態,0表示成功,其他任何值都表示有錯誤
2、變量賦值
變量=值
任何變量無需事先聲明,可直接使用
值默認都是字符型
例如:a=abc, b=3
a=3(不能寫成 a = 3 ,即中間不能有空格。因在bash中是基於命令行的,中間有空格,bash會把其後的 = 和 3 看做選項或參數)
賦值:
a=4
增強型賦值:
+=, -=, *=, /=, %=
a=$[$a+1] 相當於 let a+=1 (let a+=1相當於let a=$a+1)
自加:var++, var--, ++var, --var
3、算術運算
(1)如何定義整型變量:
let VAR_NAME=INTEGER_VALUE
例如:let a=3
declare -i VAR_NAME=INTEGER_VALUE
例如:declare -i a=3
注意:即使沒有定義爲整型變量,字符型的數字依然可以參與算術運算;bash會執行變量類型的隱式類型轉換;
(2)實現算術運算的方式:
let VAR_NAME=ARITHMATIC_EXPRESSION
( 使用let進行算術運算,要使用結果,必須把運算結果存儲在變量中,再去引用變量(不可用` `引用該命令的執行結果) )
VAR_NAME=$[ARITHMATIC_EXRESSION]
(不是命令,而是表達式)
VAR_NAME=$((EXPRESSION))
(不是命令,而是表達式)
VAR_NAME=$(expr $num1 + $num2)
(使用expr進行算術運算,可用` `引用該命令的執行結果)
(3)算術運算符:
+ :加
- :減
* :乘
/ :除
%:取模,取餘數
**: 次方,如: 2**2
4、條件測試
命令執行成功與否即爲條件測試
test EXPR
[ EXPR ]
[[ EXPR ]]
比較運算:
>, <, >=, <=, ==, !=
(1)測試類型:根據比較時的操作數的類型
整型測試:整數比較
字符測試:字符串比較
文件測試:判斷文件的存在性及屬性等
注意:比較運算通常只在同一種類型間進行
(2)整型測試:
-gt: 大於,例如 [ $num1 -gt $num2 ]
-lt: 小於
-ge: 大於等於
-le: 小於等於
-eq: 等於
-nq: 不等於
(3)字符串測試:
雙目
> 大於,例如[[ "$str1" > "$str2" ]]
< 小於
>= 大於等於
<= 小於等於
== 等於
!= 不等於
單目:
-n String: 是否不空,不空則爲真,空則爲假
-z String: 是否爲空,空則爲真,不空則假
字串測試中的模式匹配:
[[ "$var" =~ PATTERN ]]
(4)文件測試:
-a FILE :存在爲真,否則爲假;
-e FILE: 存在則爲真;否則爲假;
-f FILE: 存在並且爲普通文件,則爲真;否則爲假;
-d FILE: 存在並且爲目錄文件,則爲真;否則爲假;
-L/-h FILE: 存在並且爲符號鏈接文件,則爲真;否則爲假;
-b: 塊設備
-c: 字符設備
-S: 套接字文件
-p: 命名管道
-s FILE: 存在並且爲非空文件則爲值,否則爲假;
-r FILE :是否可讀
-w FILE :是否可寫
-x FILE :是否可執行
file1 -nt file2: file1的mtime新於file2則爲真,否則爲假;
file1 -ot file2:file1的mtime舊於file2則爲真,否則爲假;
5、if語句
(1)單分支的if語句: if 測試條件; then 選擇分支 fi 表示條件測試狀態返回值爲0時,則執行選擇分支 或者另外一種格式: if 測試條件 then 選擇分支 fi (2)雙分支的if語句: if 測試條件; then 選擇分支1 else 選擇分支2 fi 兩個分支僅執行其中之一。 (3)多分支的if語句: if 條件1; then 分支1 elif 條件2; then 分支2 elif 條件3; then 分支3 ... else 分支n fi
5、case語句
case 語句:有多個測試條件時,case語句會使得語法結構更明晰 格式: case 變量引用 in PATTERN1) 分支1 ;; PATTERN2) 分支2 ;; ... *) 分支n ;; esac PATTERN:類同於文件名通配機制,但支持使用|表示或者; a|b: a或者b *:匹配任意長度的任意字符 ?: 匹配任意單個字符 []: 指定範圍內的任意單個字符 (區分字母大小寫) t-size:14px; font-family:'宋體'; " >**: 2**2 (分支後的“;;”表示分支結束,不再往下執行,相當於Java中的switch 中的break。如果進入分支1,不加“;;”,則會繼續往下執行。) (注意:在bash編程中,case的分支中必須加上“;;”,如果不加“;;”或僅加了“;”,會有語法錯誤!!!)
6、for語句
格式: for VAR_NAME in LIST do 循環體 done 或者可以寫成: for VAR_NAME in LIST ;do 循環體 done LIST:列表,中間包括一個或多個元素 退出條件:遍歷結束 for的第二種使用格式 : for ((初始條件;測試條件;修改表達式)); do 循環體 done
7、while語句
while 測試條件; do 循環體 done 如測試結果爲“真”,則進入循環;退出條件爲,測試條件爲假;
8、until語句
until 測試條件; do 循環體 done 如果測試結果爲“假”,則進入循環;退出條件爲,測試條件爲真;
9、函數
(函數要先定義,然後才能使用)
語法: 兩種格式: function F_NAME { 函數體 } F_NAME() { 函數體 }
可調用:使用函數名
函數名出現的地方,會被自動替換爲函數;
函數中的變量:
(1)本地變量:作用域爲整個bash進程
varname=value
(2)局部變量:作用域只對當前代碼段有效(只在函數中有效)
local varname=value (使用local關鍵字定義)
(3)環境變量:作用域爲當前shell進程及其子進程
export varname=value
函數的返回值:
函數的執行結果返回值:代碼的輸出
函數中的打印語句:echo, print
函數中調用的系統命令執行後返回的結果
執行狀態返回值:
函數體中最後一次執行的命令狀態結果
自定函數執行狀態的返回值:return #
函數可以接受參數:
在函數體中調用函數參數的方式同腳本中調用腳本參數的方式:位置參數
$1, $2, ...
$# :參數個數
$*, $@ :取所有參數