shell指令碼學習筆記
shell指令碼的格式
shell指令碼預設副檔名為.sh
。在shell指令碼中,你寫入的內容,會預設當成一條命令來執行。
例如:
#!/bin/bash echo 'hello world'
- 第1行 指定shell指令碼的預設直譯器
- 第2行 執行echo命令
將上面的程式碼存為test.sh,並將可執行許可權賦予它chmod +x test.sh
,執行./test.sh
執行指令碼。
上面的指令碼將會輸出:
hello world
註釋
和所有的程式語言一樣,shell也有註釋,在shell中,#號和它後面的內容來表示一個註釋:
# Print a message echo "I'm a shell script."
輸出內容
echo用於向輸出流輸出內容,例如:
echo "hello world"
輸入內容
read關鍵字用於輸入一條內容:
read input echo $input
上面的程式碼中,read關鍵字從輸入流讀取一個值並賦予input,然後將input的內容打印出來
1. 變數
定義變數和賦值
變數的命名規則和C語言差不多,支援英文字母和下劃線。shell中變數名前不需要宣告型別,變數名後面不能有空格,例如:
var1='hello' var2=90
讀取變數
$後接變數名意為讀取一個變數的值,例如:
var="hello" echo $var
也可以用${var}
方式訪問到變數值,例如:
var="hello" echo ${var}
訪問變數的時候$var
和${var}
是等效的,推薦後者來訪問一個變數
變數作用域
全域性變數
沒有任何關鍵字修飾的變數是一個全域性變數,全域性變數在同一個shell會話中都是有效的。可以跨檔案
function func(){ a=90 } func echo $a
輸出:
90
$ a=90 $ echo ${a} $ bash $ echo ${a}
輸出:
90
空值
區域性變數
local關鍵字用於宣告一個區域性變數
function func(){ local a=90 } func echo $a
輸出:
空值
環境變數
用export關鍵字修飾的變數稱為環境變數,在父shell會話中宣告一個環境變數,子shell中都可以訪問
$ export path="/system/bin" $ bash #建立一個新的shell會話 $ echo ${path}
特殊變數
變數 | 含義 |
---|---|
$0 | 當前指令碼的檔名 |
$n(n≥1) | 傳遞給指令碼或函式的引數。n 是一個數字,表示第幾個引數。例如,第一個引數是 $1,第二個引數是 $2 |
$# | 傳遞給指令碼或函式的引數個數 |
$* | 傳遞給指令碼或函式的所有引數 |
$@ | 傳遞給指令碼或函式的所有引數 |
$? | 上個命令的退出狀態,或函式的返回值 |
$$ | 當前 Shell 程序 ID。對於 Shell 指令碼,就是這些指令碼所在的程序 ID |
$*和$@的區別
- $*得到所有引數的字串形式
- $@得到所有引數的陣列形式,可以直接遍歷
2. 獲取一條命令的執行結果
用 ` 將一條命令包裹起來
` 這個符號,在鍵盤上的位置是在Esc鍵的下方
ret=${pwd} echo ${ret}
在 ` 包裹起來的命令中,也可以訪問到變數
path='/' ret=`ls -l ${path}` echo ${ret}
以$(command)這種方式執行命令
ret=$(pwd) echo ${ret}
用$(command)這種方式也可以訪問到變數
path='/' ret=$(ls -l ${path}) echo ${ret}
上面的例子中,如果想列印命令結果中的換行符,則:
path='/' ret=$(ls -l ${path}) echo "${ret}"
$(command)方式來執行命令更加直觀,但是要注意,$() 僅在 Bash Shell 中有效,而反引號可在多種 Shell 中都可使用
3. 字串
Shell有三種方式可以表示字串
字串的表示
(1)變數名後直接跟上字元
str=hello echo ${str}
輸出:
hello
這種方式的字串遇到空格,$等分隔符就會被終止
(2)單引號
str=hello echo '${str}'
輸出:
${str}
單引號裡的內容是字串原始的樣子,不存在轉義
(3)雙引號
str=shell echo "${str}:\"hello wolrd\""
輸出:
shell:"hello world"
雙引號中可以訪問變數和轉義
字串的長度
str="hello" echo ${#str}
字串拼接
兩個變數放在一起訪問就可以拼接
a='hello' b='world' c=${a}${b} echo ${c}
輸出:
helloworld
字串擷取
(1) 從左邊開始擷取字串,格式:${string: start :length}
,length可省略,省略時,是擷取到字串末尾
msg="hello world" echo ${msg: 6: 5}
輸出:
world
(2) 在指定位置擷取字元
-
擷取chars後面的字元:
${string#*chars}
其中,string 表示要擷取的字元,chars 是指定的字元(或者子字串),是萬用字元的一種,表示任意長度的字串。 chars連起來使用的意思是:忽略左邊的所有字元,直到遇見 chars(chars 不會被擷取)。
-
擷取最後一次出現chars的位置後面的內容:
${string##*chars}
-
使用 % 擷取左邊字元
使用%號可以擷取指定字元(或者子字串)左邊的所有字元,具體格式如下:
${string%chars*}
請注意 * 的位置,因為要擷取 chars 左邊的字元,而忽略 chars 右邊的字元,所以 * 應該位於chars的右側。其他方面%和#的用法相同
4. 運算子和流程控制
基本運算
運算子 | 作用 |
---|---|
+ | 加(需要結合expr命令使用) |
- | 減(需要結合expr命令使用) |
* | 乘(需要結合expr命令使用) |
/ | 除(需要結合expr命令使用) |
% | 求餘(需要結合expr命令使用) |
= | 賦值 |
== |
判斷數值是否相等,需要結合[]
使用 |
!= |
判斷數值是否不相等,需要結合[]
使用 |
a=8 b=4 echo "a=$a,b=$b" var=`expr ${a} + ${b}` echo "加法結果:${var}" var=`expr ${a} - ${b}` echo "減法結果:${var}" # 注意:乘號需要轉義 var=`expr ${a} \* ${b}` echo "乘法結果:${var}" var=`expr ${a} / ${b}` echo "除法結果:${var}" var=`expr ${a} % ${b}` echo "求餘結果:${var}" var=$[${a} == ${b}] echo "是否相等:${var}" var=$[${a} != ${b}] echo "是否不相等:${var}"
輸出:
a=8,b=4 加法結果:12 減法結果:4 乘法結果:32 除法結果:2 求餘結果:0 是否相等:0 是否不相等:1
上面的例子中,呼叫expr命令和使用[]
,得到表示式的值,並將它們輸出
請注意表示式兩邊的空格,shell中表達式兩邊要有空格
關係運算
運算子 | 作用 |
---|---|
-eq | 全稱:Equal,判斷兩個數是否相等 |
-ne | 全稱:Not equal,判斷兩個數是否不相等 |
-gt | 全稱:Greater than,判斷前面那個數是否大於後面那個數 |
-lt | 全稱:Less than,判斷前面那個數是否小於後面那個數 |
-ge | 全稱:Greater equal,判斷前面那個數是否大於等於後面那個數 |
-le | 全稱:Less than,判斷前面那個數是否小於等於後面那個數 |
布林運算
運算子 | 作用 |
---|---|
! | 非運算 |
-o | 或運算 |
-a | 並運算 |
邏輯運算
運算子 | 作用 |
---|---|
&& | 邏輯並 |
|
|
邏輯或 |
檔案判斷
運算子 | 作用 |
---|---|
-e | 判斷物件是否存在 |
-d | 判斷物件是否存在,並且為目錄 |
-f | 判斷物件是否存在,並且為常規檔案 |
-L | 判斷物件是否存在,並且為符號連結 |
-h | 判斷物件是否存在,並且為軟連結 |
-s | 判斷物件是否存在,並且長度不為0 |
-r | 判斷物件是否存在,並且可讀 |
-w | 判斷物件是否存在,並且可寫 |
-x | 判斷物件是否存在,並且可執行 |
-O | 判斷物件是否存在,並且屬於當前使用者 |
-G | 判斷物件是否存在,並且屬於當前使用者組 |
-nt | 判斷file1是否比file2新 |
-ot | 判斷file1是否比file2舊 |
流程控制語句
(1) if語句
if語句格式如下:
if [ <condition> ] then #do something elif [ <condition> ] then #do something else #do something fi
如果想把then和if放同一行
if [ <condition> ] ; then #do something elif [ <condition> ] ; then #do something else #do something fi
其中elif和else可以省略
例子:
read file if [ -f ${file} ] ; then echo 'This is normal file.' elif [ -d ${file} ] ; then echo 'This is dir' elif [ -c ${file} -o -b ${file} ] ; then echo 'This is device file.' else echo 'This is unknown file.' fi
邏輯判斷也可以用test命令,它和[]
的作用是一樣的
#!/bin/bash a=4 b=4 if [ $[a+1] -eq $[b+2] ] then echo "表示式結果相等" else echo "表示式結果不相等" fi
輸出:
表示式結果不相等
(2) for 語句
if語句格式如下:
for [ <var> ] in [list] do # do something done
例子:
read input for val in ${input} ; do echo "val:${val}" done
輸入:
1 2 3 4 5
輸出:
val:1
val:2
val:3
val:4
val:5
(3) while 語句
while [ <condition> ] do #do something done
例子:
a=1 sum=0 while [ ${a} -le 100 ] ;do sum=`expr ${sum} + ${a}` a=`expr ${a} + 1` done echo ${sum}
輸出:
5050
5. 函式
- 用function關鍵字來定義一個函式
- 直接寫一個函式名來呼叫一個無引數的函式
- 函式有引數,呼叫時,在函式名後面寫上引數,多個引數用空格隔開
- 呼叫函式時傳遞引數,在函式體內部,通過 $n的形式來獲取引數的值,例如:$1表示第1個引數,$2表示第2個引數...
函式的結構
function foo(){ # do everything... }
函式的用法示例
function foo(){ local name=$1 local age=$2 echo "My name is: ${name},I'm ${age} years old." } foo "luoye" 26
輸出:
My name is: luoye,I'm 26 years old.
6. 參考
http://c.biancheng.net/shell/
http://www.runoob.com/linux/linux-shell-process-control.html
https://www.cnblogs.com/qlqwjy/p/8684630.html