shell指令碼學習手冊
簡介:
Shell 是一個用C語言編寫的程式,它是使用者使用Linux的橋樑。Shell既是一種命令語言,又是一種程式設計語言。
Shell 是指一種應用程式,這個應用程式提供了一個介面,使用者通過這個介面訪問作業系統核心的服務。
Ken Thompson的sh是第一種Unix Shell,Windows Explorer是一個典型的圖形介面Shell。
Shell教程入門
1、shell指令碼
shell指令碼shell script,是一種為shell而編寫的指令碼程式。然而通常所說的shell卻是指shell指令碼,而非shell本身。
Linux系統shell種類眾多,常用的有
2、shell指令碼實踐
shell指令碼用#!/bin/bash或#!/bin/sh之類的方式,制定執行指令碼的shell,#!是識別符號。
- #!/bin/sh
- echo "Hello World"
執行shell指令碼的兩種方法:
- 作為可執行程式
將shell文字儲存為.sh格式檔案,賦予執行許可權
-
- chmod + x ./test.sh # 賦予可執行許可權
- ./test.sh #執行指令碼,注意此處需要指明當前目錄下的test.sh哦,不然會去path路徑找的,呵呵。
- 作為解釋其引數
直接解釋執行,如此就不用寫#!/bin/sh之類的引用註釋了。
-
- /bin/sh test.sh
- # 類似java、php、python指令碼
- /bin/php test.php
Shell變數
變數命名語法,不需要$符號,php需要。命名要求:
- 首字母必須字母a-z或A-Z
- 不能空格,可用_
- 不能標點
- 不能使用bash關鍵字
- #注意,不同於其他程式語言,等號之間不要有空格。
- your_variable=
- # 使用語句給變數賦值,如下迴圈顯示出/etc目錄下的檔名
- for file in 'ls /etc'
1、使用變數
使用已定義變數,只需在變數前加$符號即可:
- your_variable='yourname'
- echo $your_variable
- echo $(your_variable)
變數名可以加{}來標識變數名的範圍,如:
- for skill in Ada Coffe Action Java; do
- echo "I am good at ${skill}Script"
- done
如果不加{},skill就可能被認為skillScript而導致變數找不到
已定義的變數可重新定義:
- your_name="tom"
- echo $your_name
- your_name="john"
- echo $your_name
2、只讀變數
使用readonly命令將變數只讀,則不可再改變,否則報錯。
- #!/bin/bash
- myUrl="http://www.w3cschool.cc"
- readonly myUrl
- myUrl="new url" #此處就會報錯,因為變數只讀了。
3、刪除變數
使用unset命令刪除變數:
unset variable_name
==刪除變數後不能再用,而unset不能刪除只讀變數==
- #!/bin/sh
- myUrl="http://www.google.com"
- unset myUrl
- echo $myUrl #此時輸出就沒接過了,因為變數被刪除了。
4、變數型別
執行shell時,會同時存在三種變數:
- 區域性變數:指令碼中定義的變數,僅作用於本shell指令碼內。
- 環境變數:所有程式,包括shell啟動程式都能訪問的環境變數。
- shell變數:shell程式的特殊變數。
5、shell字串
shell常用number和string,其中string可以單引號、雙引號或者不用引號。但是略有區別:
- 單引號
str='string test'
單引號''之間的字元原樣輸出,裡面的變數也會失效。其內部不能再有單引號,哪怕轉義符號都失效。
- 雙引號
- your_name='your name'
- str="Hello ,world ,\"$your_name\"! \n"
雙引號裡面可以有變數,可以有轉義符號。
- 字串拼接
- n1="abc"
- test="hello, "$n1" !"
- test1="hello, ${n1} !"
- echo $test $test1
- 獲取字串長度
使用#標識變數長度
-
- str="abcdef"
- #輸出字串長度
- echo ${#str}
- 獲取子字串
- str="abcdef"
- #下標從左至右,0開始,
- echo ${str:1:4}
- 查詢子字串
使用`符號
-
- str="hello world nihaome"
- #查詢字元i或s的位置,反引號
- echo `expr index "$str" is`
6、Shell陣列
bash僅支援一維陣列,可利用下標或表示式操作元素。
- 定義陣列
shell中使用()表示陣列,元素用空格來分割。
-
- array=(1 2 3 4 5 6 7)
- #或者
- array=(
- a
- b
- c
- )
- #也可以單獨定義,下標可以不連續,也無範圍限制。
- array[0]=1
- array[1]=2
- array[3]=7
- 讀取陣列
- variable=${array[index]}
- # @符號代替index表示獲取所有元素
- echo ${variable[@]}
- 獲取陣列長度
類似字串的獲取
-
- #獲取元素個數
- length=${#array_name[@]}
- #或者*萬用字元
- length=${#array_name[*]}
- #獲取陣列單個元素的長度
- length_n=${#array_name[n]}
7、Shell註釋
使用#至於行首,表示該行註釋,shell無多行註釋,只能每行都#
- #-----------------------
- #我是個多行註釋
- #但是隻能這麼寫
- #-----------------------
要是多行程式碼需要註釋,可以將定義為函式,加{}包裹起來,該函式不被呼叫,則類似於註釋掉。
Shell傳遞引數
在執行shell指令碼時,可以向指令碼傳遞引數,指令碼內獲取引數的格式:$n,n代表數字編號,為指令碼內需要獲取的引數的編號。
1、例項
示例向指令碼傳遞三個引數,並輸出,$0為執行檔名:
- #!/bin/bash
- #傳參測試
- echo "Shell 傳參測試";
- echo "file name: $0";
- echo "first variable: $1";
- echo "second variable: $2"
- echo "third variable: $3";
通過賦予許可權,或者指定執行,可實現輸出:
- $ chmod +x test.sh
- # $符號在次表示root使用者執行,下面是傳入1,2,3,三個數到指令碼
- $ ./test.sh 1 2 3
- #輸出結果:
- Shell 傳參測試
- file name: ./test.sh
- first variable: 1
- second variable 2
- third variable 3
另有幾個特殊字元處理引數:
引數處理 |
說明 |
$# |
傳遞到指令碼的引數的個數 |
$* |
以一個單字串顯示所有向指令碼傳遞的引數。 |
$$ |
指令碼執行的當前程序ID號 |
$! |
後臺執行的最後一個程序的ID號 |
類似$*,使用時許加引號,並在引號中返回每個引數。 |
|
$- |
顯示shell使用的當前選選項,類似set命令 |
$? |
顯示最後命令的退出狀態。0 表示無錯誤。其他都是錯。 |
- #!/bin/sh
- echo "Shell 傳遞引數例項!";
- echo "第一個引數為:$1";
- echo "引數個數為:$#";
- echo "傳遞的引數作為一個字串顯示:$*";
執行效果:
- $ chmod +x test.sh
- $ ./test.sh 1 2 3
- Shell 傳遞引數例項!
- 第一個引數為:1
- 引數個數為:3
- 傳遞的引數作為一個字串顯示:1 2 3
$*與[email protected]的異同:
- 都是應用所有引數
- 不同:只有在雙引號中體現。假設在指令碼執行時寫了三個引數 1、2、3,,則 ” * ” 等價於 “1 2 3”(傳遞了一個引數),而 “@” 等價於 “1” “2” “3”(傳遞了三個引數)。
- #!/bin/bash
- echo "-- \$* demo ---"
- for i in "$*";do
- echo $i
- done
- echo "-- \[email protected] demo ---"
- for i in "[email protected]"; do
- echo $i
- done
執行效果:
-
- $ chmod +x test.sh
- $ ./test.sh 1 2 3
- -- $* 演示 ---
- 1 2 3
- -- [email protected] 演示 ---
- 1
- 2
- 3
Shell陣列
Bash shell僅支援一維陣列,不限定大小,初始化時候不需要指定大小。下標0開始,()包裹,空格分割元素。
array=(a b c d)
- 讀取陣列
格式${array[index]}
- #!/bin/bash
- my_array=(a b "c" d)
- echo "first: ${my_array[0]}"
- #然後執行檔案,獲得輸出結果
- #可用@或*來代替index獲取所有元素
- 陣列長度
類似字串的長度獲取
${#array[index]}
Shell運算子
shell支援多種運算子:
- 算數運算子
- 關係運算符
- 布林運算子
- 字串運算子
- 檔案測試運算子
原生Bash不支援簡單的數學運算,可以用awk和expr實現。
- #!/bin/sh
- val=`expr 2 + 2`
- echo $val
- #注意,expr用反引號,表示式和運算子之間必須有空格,2+2就不行。
1、算術運算子
若a = 10,b = 20
運算子 |
說明 |
舉例 |
+ |
加號 |
`expr $a + $b`,result = 30 |
- |
減號 |
`expr $a - $b`,result = -10 |
* |
乘號 |
`expr $a * $b`,result = 200 |
/ |
除號 |
`expr $b / $a`,result = 2 |
% |
取餘 |
`expr $b % $a`,result=0 |
= |
賦值 |
a=$b,將b的值賦給a |
== |
相等,比較數字,同則true。 |
[$a == $b]返回false |
!= |
不等,比較數字,不同的true。 |
[$a != $b]返回true。 |
- #!/bin/bash
- # author:菜鳥教程
- # url:www.runoob.com
- a=10
- b=20
- val=`expr $a + $b`
- echo "a + b : $val"
- val=`expr $a - $b`
- echo "a - b : $val"
- val=`expr $a \* $b`
- echo "a * b : $val"
- val=`expr $b / $a`
- echo "b / a : $val"
- val=`expr $b % $a`
- echo "b % a : $val"
- if [ $a == $b ]
- then
- echo "a 等於 b"
- fi
- if [ $a != $b ]
- then
- echo "a 不等於 b"
- fi
執行結果:
- a + b : 30
- a - b : -10
- a * b : 200
- b / a : 2
- b % a : 0
- a 不等於 b
注意:條件表示式必須在[]之間,且必須有空格,如[$a==$b]是錯的!
*乘號需要在expr表示式內用\轉義
Mac電腦的shell的expr表示式:$((表示式))所以它的乘號*不用轉義
2、關係運算符
布林型別,關係運算符僅支援數字,除非字串的值也是數字。示例,若a = 10 ,b = 20:
運算子 |
說明 |
-eq |
equal |
-ne |
not equal |
-gt |
great than |
-lt |
less than |
-ge |
great equal |
-le |
less equal |
3、布林運算子
運算子 |
說明 |
! |
非運算,表示式為true,則返回false。 |
-o |
或運算,一個表示式為true,則返回true。 |
-a |
與運算,兩個都true,才返回true。 |
4、邏輯運算子
運算子 |
說明 |
&& |
邏輯and |
|| |
邏輯 or |
5、字串運算子
運算子 |
說明 |
= |
檢測兩字串是否相等 |
!= |
檢測兩字串是否不等 |
-z |
zero檢測字串長度是否為0,0則true |
-n |
not zero檢測字串長度是否非0。 |
str |
檢測字串是否為空,不空則true。 |
6、檔案測試運算子
用於檢測類unix 檔案的各種屬性
操作符 |
說明 |
-b file |
是否是塊裝置檔案,是則true |
-c file |
是否是字元裝置檔案,是則true |
-d file |
是否是目錄,是則true |
-f file |
是否是普通檔案(既非目錄,亦非裝置檔案),若是則true |
-g file |
是否設定了SGID位,是則true |
-k file |
是否設定粘著位,是則true |
-p file |
是否有名管道,是則true |
-u file |
是否設定SUID,是則true |
-r file |
是否可讀,是則true |
-w file |
是否可寫,是則true |
-x file |
是否可執行,是則true |
-s file |
是否為空或大小是否大於0,非空則true |
-e file |
是否存在,是則true |
==注意shell指令碼的表示式都要在[]內哦==
Shell echo命令
類似於php的echo,shell的echo用於輸出字串,格式echo string
- 顯示普通字串
- echo "Hello World"
- #可以不帶引號
- echo Hello World
- 顯示轉義字元
- echo "\"It is a test\""
- #輸出結果
- "It is a test"
-
- 顯示變數
read命令從標準輸入中讀取一行,並把輸入行的每個欄位指定給shell變數
-
- #!/bin/sh
- read name
- echo "$name It is a test"
- #執行效果:
- [[email protected] ~]# sh test.sh
- OK #標準輸入
- OK It is a test #輸出
-
- 顯示換行
- echo -e "Ok ! \n" # -e 開啟轉義
- echo "It is a test"
- #輸出結果:注意ok後面有換行
- OK!
- It it a tes
-
- 顯示不換行
- #!/bin/sh
- echo -e "OK! \c" # -e 開啟轉義 \c 不換行
- echo "It is a test"
- #結果:
- OK! It is a test
-
- 顯示結果定向至檔案
echo "It is a test" > test.txt
-
- 1
- 原樣輸出字元,不轉義不取變數,需要結合單引號
- echo '$name\"'
- #輸出結果
- $name\"
- 顯示命令執行結果
==命令用`來包裹==
-
- echo `data`
- #結果:
- Thu Jul 24 10:08:46 CST 2014
Shell printf命令
類似C語言的printf()函式,shell使用printf會比echo更具有跨平臺移植性。可以類似C的printf()函式使用一些複雜的表示式,printf不支援自動換行,需要藉助\n
printf format-string [args...]
- 1
示例,模擬shell輸出,
- $ echo "hello ,shell"
- hello ,shell
- $ printf "hello ,shell \n"
- hello ,shell
- $
指令碼化的printf命令使用:
- #!/bin/bash
- # author:菜鳥教程
- # url:www.runoob.com
- printf "%-10s %-8s %-4s\n" 姓名 性別 體重kg
- printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
- printf "%-10s %-8s %-4.2f\n" 楊過 男 48.6543
- printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876
執行指令碼,顯示結果:
- 姓名 性別 體重kg
- 郭靖 男 66.12
- 楊過 男 48.65
- 郭芙 女 47.99
%s,%c,%d,%f都是格式替換符,%-10s指一個寬度為10個字元(-表示左對齊,沒有則右對齊),任何字元都會被顯示在10個字元寬的字元內,如果不足則自動以空格填充,超過也會將內容全部顯示出來。
%-4.2f 指格式化為小數,其中.2指保留2位小數。
- #!/bin/bash
- # author:菜鳥教程
- # url:www.runoob.com
- # format-string為雙引號
- printf "%d %s\n" 1 "abc"
- # 單引號與雙引號效果一樣
- printf '%d %s\n' 1 "abc"
- # 沒有引號也可以輸出
- printf %s abcdef
- # 格式只指定了一個引數,但多出的引數仍然會按照該格式輸出,format-string 被重用
- printf %s abc def
- printf "%s\n" abc def
- printf "%s %s %s\n" a b c d e f g h i j
- # 如果沒有 arguments,那麼 %s 用NULL代替,%d 用 0 代替
- printf "%s and %d \n"
- 2
Printf的轉移序列
序列 |
說明 |
\a |
警告字元,通常為ASCII的BEL字元 |
\b |
後退 |
\c |
抑制不顯示輸出結果中任何姐wide換行字元(只在%b格式指示控制符下的引數字串中有效),而且任何留在引數裡的字元,任何接下來的採納書以及任何留在格式字串中的字元,都被忽略。 |
\f |
換頁 |
\n |
換行 |
\r |
回車 |
\t |
水平tab |
\v |
豎直tab |
\\ |
轉義後輸出一個\符號 |
\d dd |
表示1–3位的八進位制字元,僅在格式字串中有效。 |
\0 dd d |
表示1–3位的八進位制字元 |
Shell text命令
shell中test命令用於測試條件是否成立,可進行數字、字元和檔案的條件測試
- #!/bin/bash
- #用之前的各種運算子,測試test
- num1=100
- num2=200
- if test $[num1] -eq $[num2]
- then
- echo 'true'
- else
- echo 'false'
- fi
Shell 流程控制
區別於其他程式語言,shell的流程控制不可為空,如
- if(a>b){
- System.out.println("ok");
- }else{
- //此處不做任何事
- }
但是在shell中不能出現不做任何事的分支語句
1、if else
- if語句格式
- if condition
- then
- command1
- command2
- ...
- fi # 是if的倒寫
每個句子可以用;分號結束,可以寫在一行好幾個語句。
- if else
- if condition
- then
- command1
- command2
- ...
- else
- command
- fi
-
- if else-if else
- if condition1
- then
- command1
- elif condition2 #類似python中,else if是寫作elif
- then
- command2
- else
- command
- fi
-
- 9
2、for迴圈
shell的for迴圈格式:
- for var in item1 item2 ... itemN
- do
- command1
- command2
- ...
- done #for迴圈結束的標識
- #寫成一行
- for var in item1 item2 ... itemN;do command1; command2;...;done;
- 9
3、while語句
格式:
- while condition
- do
- command
- done
- #示例
- #!/bin/sh
- int=1
- while(( $int<=5 ))
- do
- echo $int
- let "int++" # let是個關鍵命令
- done
- 3
可以結合read命令接收輸入資訊
4、無限迴圈
- while :
- do
- command
- done
- #或者
- while true
- do
- command
- done
- #或者
- for (( ; ; ))
5、until迴圈
shell所有的until迴圈類似於一個特殊的for迴圈,知道滿足條件時候才停止。一般還是while
- until condition
- do
- command
- done
條件可為任意測試條件,測試發生在迴圈末尾,因此迴圈至少執行一次—請注意這一點。
6、case
類似其他語言的switch…case語句
- case value in
- mode1)
- command1
- ...
- ;; #case的結束標誌
- mode2)
- command2
- ...
- ;;
- esac #case的反寫
value只會匹配一個case,或者不匹配,則mode可用*號通配
- echo '輸入 1 到 4 之間的數字:'
- echo '你輸入的數字為:'
- read aNum
- case $aNum in
- 1) echo '你選擇了 1'
- ;;
- 2) echo '你選擇了 2'
- ;;
- 3) echo '你選擇了 3'
- ;;
- 4) echo '你選擇了 4'
- ;;
- *) echo '你沒有輸入 1 到 4 之間的數字'
- ;;
- esac
7、跳出迴圈
shell也使用break和continue來跳出迴圈。
- break
跳出所有迴圈,終止後面的執行。
-
- #!/bin/bash
- while :
- do
- echo -n "輸入 1 到 5 之間的數字:"
- read aNum
- case $aNum in
- 1|2|3|4|5) echo "你輸入的數字為 $aNum!"
- ;;
- *) echo "你輸入的數字不是 1 到 5 之間的! 遊戲結束"
- break
- ;;
- esac
- done
- continue
跳出本次迴圈,執行下一輪迴圈
-
- #!/bin/bash
- while :
- do
- echo -n "輸入 1 到 5 之間的數字: "
- read aNum
- case $aNum in
- 1|2|3|4|5) echo "你輸入的數字為 $aNum!"
- ;;
- *) echo "你輸入的數字不是 1 到 5 之間的!"
- continue
- echo "遊戲結束"
- ;;
- esac
- done
8、esac
case語句區別於C語言,用esac作為結束標誌,)和;;標識每個case。
Shell函式
shell可以自定義函式,然後自己呼叫。函式格式:
- #function 關鍵字為可選項,引數也是可選
- [ function ] funname [()]
- {
- action;
- [return int;]
- }
說明:
- 可以帶function fun()定義,也可以fun()定義,不帶引數。
- 引數返回,可以顯示加: return 返回,若不加,則返回最後一條指令結果。
- #!/bin/bash
- # author:菜鳥教程
- # url:www.runoob.com
- demoFun(){
- echo "這是我的第一個 shell 函式!"
- }
- echo "-----函式開始執行-----"
- demoFun
- echo "-----函式執行完畢-----"
- 0
含有返回值的函式:
- #!/bin/bash
- # author:菜鳥教程
- # url:www.runoob.com
- funWithReturn(){
- echo "這個函式會對輸入的兩個數字進行相加運算..."
- echo "輸入第一個數字: "
- read aNum
- echo "輸入第二個數字: "
- read anotherNum
- echo "兩個數字分別為 $aNum 和