1. 程式人生 > 其它 >shell學習[三]:流程控制語句與函式

shell學習[三]:流程控制語句與函式

1.Shell整數計算命令

1.1 expr表示式求值命令

expr (evaluate expressions 的縮寫),譯為“表示式求值”。Shell expr 是一個功能強大,並且比較複雜的命令,它除了可以實現整數計算,還可以結合一些選項對字串進行處理,例如計算字串長度、字串比較、字串匹配、字串提取等.

計算語法

expr 算術運算子表示式
# 例如: expr 1 + 1  返回: 2
# 例如: expr \( 10 + 10 \) \* 2 + 100 返回:140

abc@aliyun:~$ expr \( 10 + 10 \) \* 2 + 100
140

獲取計算結果賦值給新變數語法

result=`expr 算術運算子表示式`
# 例如: result=`expr 1 + 1`  輸出result得到結果: 2

計算字串的長度語法

expr length 字串
# 例如: expr length "itheima"  返回: 7

擷取字串語法

expr substr 字串 start end
# start 擷取字串的起始位置, 從1開始
# end 擷取字串的結束位置, 包含這個位置擷取
# 例如 expr substr "itheima" 1 2  返回: it

獲取第一個字元在字串中出現的位置語法

expr index 被查詢字串  需要查詢的字元
# 例如 expr index "itheima" t  會返回: 2 

正則表示式匹配1語法

expr match 字串 正則表示式
# 正則表示式預設帶有^ ,  代表以什麼開頭
# 返回值為符合匹配字元的長度, 否則返回為0
# 例如: expr match "itheima" ".*m"  會返回: 6
# 正則表示式萬用字元"."代表任意一個字元
# 正則表示式萬用字元"*"代表簽名的字元可以出現0到多次
# ".*m" 含義為匹配字串中m前面的字串長度 

正則表表達式匹配2語法, 功能與語法1一樣

expr 字串 : 正則表示式
# 正則表示式預設帶有^ ,  代表以什麼開頭
# 返回值為符合匹配字元的長度, 否則返回為0
# 例如: expr "itheima" : ".*m"  會返回: 6

演示

#!/bin/bash
# 四則運算
result=`expr \( 10 + 10 \) \* 2 + 100`
echo "(10+10)*2+100=${result}"

# 計算字串的長度
echo "itheima字串長度=`expr length "itheima"`"

# 獲取第一個字元在字串中出現的位置
echo "itheima字串中第一個t的位置=`expr index "itheima" t`"

# 正則表示式匹配1
echo "正則表示式match匹配查詢itheima字串中m前面任意字元的總長度=`expr match "itheima" ".*m"`"

# 正則表示式匹配2
echo "正則表示式匹配查詢itheima字串中m前面任意字元的總長度=`expr "itheima" : ".*m"`"

1.2 (())命令詳解

雙小括號 (( )) , 用於進行數學運算表示式的執行 , 將數學運算表示式放在(())之間。

可以使用$獲取 (( )) 表示式命令的結果,這和使用$獲得變數值是一樣的。

語法

((表示式))

用法

運算操作符/運算命令 說明
((a=1+6))
((b=a-1))
((c=a+b))
這種寫法可以在計算完成後給變數賦值。以 ((b=a-1)) 為例,
即將 a-1 的運算結果賦值給變數 c。 注意,使用變數時不用加$字首,
(( )) 會自動解析變數名。
a=$((1+6)
b=$((a-1))
c=$((a+b))
可以在 (( )) 前面加上$符號獲取 (( )) 命令的執行結果,
也即獲取整個表示式的值。以 c=$((a+b)) 為例,即將 a+b 這個
表示式的運算結果賦值給變數 c。 注意,如果 c=((a+b)) 這樣的寫
法是錯誤的,不加$就不能取得表示式的結果。
((a>7 && b==c)) (( )) 也可以進行邏輯運算,在 if 語句中常會使用邏輯運算。
echo $((a+10)) 需要立即輸出表達式的運算結果時,可以在 (( )) 前面加$符號。
((a=3+5, b=a+10)) 對多個表示式同時進行計算, 多表表示式使用","號隔開

注意: 符號之間有無空格都可以 , (( a = 1 + 6 )) 等價於 ((a=1+6))

示例

#!/bin/bash
# 計算1+6賦值給變數a
((a=1+6))

# 計算變數a-1賦值給變數b
((b=a-1))

# 計算變數a+變數b賦值給變數c
((c=a+b))

# 列印變數a,變數b, 變數c的值
echo "a=${a},b=${b},c=${c}"

# $賦值寫法
a=$((1+6)) b=$((a-1)) c=$((a+b))
echo "a=${a},b=${b},c=${c}"

# (())多個表示式計算賦值
((a=1+6,b=a-1,c=a+b))
echo "a=${a},b=${b},c=${c}"

# echo輸出直接使用(())
echo "1+6=$((1+6))"

# (()) 用於邏輯表示式 在if中使用
if ((a>7 && b==c))
then
        echo "a>7 && b==c 成立"
else
        echo "a>7 && b==c 不成立"
fi

1.3 let命令詳解

let 命令和雙小括號 (( )) 在數字計算方面功能一樣. 但是沒有(())功能強大, let只能用於賦值計算, 不能直接輸出, 不可以條件判斷一起使用

語法

let 賦值表示式

注意

  1. 語法功能等價於((表示式))

  2. 多個表示式之間使用空格, 不是","號

  3. 對於類似let a+b這樣的寫法,Shell 雖然計算了 a+b 的值,但卻將結果丟棄, 如果 echo let a+b 會直接輸出字串 a+b ;若不想這樣,可以使用let sum=a+b將 a+b 的結果儲存在變數 sum 中。

    abc@aliyun:~$ a=1 b=2
    abc@aliyun:~$ echo let a+b
    let a+b
    abc@aliyun:~$ echo $((a+b))
    3
    abc@aliyun:~$ 
    
    

    輸出建議使用(())

示例

#!/bin/bash
# 計算1+6賦值給變數a
let a=1+6

# 計算變數a-1賦值給變數b
let b=a-1

# 計算變數a+變數b賦值給變數c
let c=a+b

# 列印變數a,變數b, 變數c的值
echo "a=${a},b=${b},c=${c}"

# let多個表示式計算賦值
let a=1+6 b=a-1 c=a+b
echo "a=${a},b=${b},c=${c}"

1.4 $[]命令詳解

和 (())、let 命令類似,$[] 也只能進行整數運算。但是隻能對單個表示式的計算求值與輸出

語法

$[表示式]
  1. $[] 會對表示式進行計算,並取得計算結果

  2. 表示式內部不可以賦值給變數

示例

#!/bin/bash
# 計算1+6賦值給變數a
a=$[1+6]

# 計算變數a-1賦值給變數b
b=$[a-1]

# 計算變數a+變數b賦值給變數c
c=$[a+b]

# 列印變數a,變數b, 變數c的值
echo "a=${a},b=${b},c=${c}"

# 直接輸出
echo "$[1+6],$[7-1],$[7+6]"

1.5 bc命令詳解

Bash shell內建了對整數運算的支援,但是並不支援浮點運算,而 linux bc (basic calculator)命令可以很方便的進行浮點運算. bc命令是Linux簡單的計算器,能進行進位制轉換與計算。能轉換的進位制包括十六進位制、十進位制、八進位制、二進位制等。可以使用的運算子號包括(+)加法、(-)減法、(*)乘法、(/)除法、(^)指數、(%)餘數等

語法

bc [options] [引數]

options

選項 說明
-h help,幫助資訊
-v version,顯示命令版本資訊
-l mathlib, 使用標準數學庫, 例如使用內建函式就需要使用這個引數
-i interactive, 強制互動
-w warn, 顯示 POSIX 的警告資訊
-s standard, 使用 POSIX 標準來處理
-q quiet, 不顯示歡迎資訊

預設使用bc命令後回車會有很多歡迎資訊, 可以使用 bc -q 回車後不會有歡迎資訊

引數

檔案: 指定包含計算任務的檔案。

示例:bc執行計算任務的檔案

建立task.txt檔案, 編輯檔案內容(一個計算表示式一行)

108*67+12345
58+2007*11

執行命令

abc@aliyun:/tmp/bgtest$ bc -q cal.txt 
19581
22135

可以使用 quit 命令退出bc

內建變數

變數名 作 用
scale 指定精度,也即小數點後的位數, 對計算結果指定保留小數;預設為 0,也即不使用小數部分。
ibase 指定輸入的數字的進位制,預設為十進位制。
obase 指定輸出的數字的進位制,預設為十進位制。
last 或者 . 獲取最近計算列印結果的數字

內建數學函式

函式名 作用
s(x) 計算 x 的正弦值,x 是弧度值。
c(x) 計算 x 的餘弦值,x 是弧度值。
a(x) 計算 x 的反正切值,返回弧度值。
l(x) 計算 x 的自然對數。
e(x) 求 e 的 x 次方。
j(n, x) 貝塞爾函式,計算從 n 到 x 的階數。

作用

通常在linux下bc當計算器用, 具體有3個用法

  1. bc中互動式的數學運算
  2. shell中非互動式的管道運算
  3. shell中非互動式的輸入重定向運算

示例1:bc中互動式的數學運算

使用 bc -q 命令,回車即可, 直接進行計算器進行運算

abc@aliyun:/tmp/bgtest$ bc -q
1+1			#加
2

2^3			#冪運算
8

10/3		#除
3

10%3		#取餘數
1

m=2;n=3;m+n	#定義變數
5

scale=4;10/3	#設定小數保留4位
3.3333

ibase=2;7
7

ibase=2;111		#設定輸入為2進位制
7

obase=2;7		#設定輸出為2進位制
111

退出bc使用 quit

#使用標準數學庫, 例如使用內建函式就需要使用這個引數
abc@aliyun:/tmp/bgtest$ bc -q -l	
e(5)		#求e的5次方
148.41315910257660342111

s(5)		#求5的正弦值
-.95892427466313846889

j(5,10)		#貝塞爾函式,計算從 5 到 10 的階數
-.23406152818679364044

l(5)		#計算 5 的自然對數。
1.60943791243410037460

示例2:shell中非互動式的管道運算

在 Shell 指令碼中,我們可以藉助管道使用 bc 計算器。

藉助管道使用 bc 計算器語法

直接進行bc的表示式計算輸出

echo "expression" | bc [options]

"expression" 表示式必須符合bc命令要求的公式

"expression" 表示式裡面可以引用shell變數

例如: Shell變數 a=2 在表示式裡面引用的語法: $a

將bc計算結果賦值給Shell變數

# 第一種方式
var_name=`echo "expression" | bc [options]`

# 第二種方式
var_name=$(echo "expression" | bc [options])

$() 與 `` 功能一樣, 都是執行裡面的命令

區別

​ `` (tab鍵上面的符號)是所有linux系統支援的方式, 相容性較好, 但是容易與引號產生混淆

​ $() 不是所有linux系統都支援的方式, 相容性較差, 但是不容易產生混淆

演示

abc@aliyun:/tmp/bgtest$ echo "9*9"|bc
81
abc@aliyun:/tmp/bgtest$ result=$(echo "4+9"|bc)
abc@aliyun:/tmp/bgtest$ echo $result
13
abc@aliyun:/tmp/bgtest$ echo "scale=3;10/3"|bc
3.333
abc@aliyun:/tmp/bgtest$ echo "scale=3;10/3;last*2"|bc
3.333
6.666
abc@aliyun:/tmp/bgtest$ 

引用shell變數進行計算

abc@aliyun:/tmp/bgtest$ a=2
abc@aliyun:/tmp/bgtest$ echo "scale=2;b=$a+2;e(b)"|bc -l
54.59
abc@aliyun:/tmp/bgtest$ echo "scale=2;e(4)"|bc -l
54.59

注意 b是bc中定義的新變數, 與shell變數沒有任何關係, 所以不可以在shell中獲取b變數

進位制轉換

abc@aliyun:/tmp/bgtest$ a=111
abc@aliyun:/tmp/bgtest$ b=$(echo "ibase=2;$a"|bc)		#2進位制轉10進位制
abc@aliyun:/tmp/bgtest$ echo $b
7
abc@aliyun:/tmp/bgtest$ a=7
abc@aliyun:/tmp/bgtest$ b=$(echo "ibase=10;obase=2;$a"|bc)	#10進位制轉2進位制
abc@aliyun:/tmp/bgtest$ echo $b
111

示例3:shell中非互動式的輸入重定向運算

將計算表示式輸出給bc去執行, 特點類似於檔案中輸入,可以輸入多行表示式, 更加清晰

語法

# 第一種方式
var_name=`bc [options] << EOF
第一行表示式1
第二行表示式2
...
EOF
`

# 第二種方式
var_name=$(bc [options] << EOF
第一行表示式1
第二行表示式2
...
EOF
)

var_name 這是Shell變數的名字

bc 執行bc的命令

EOF..EOF 輸入流的多行表示式

含義: 將EOF中間多行表示式輸入給到bc去執行, j將bc執行的結果給到Shell變數var_name

演示

[root@aliyun ~]# a=100
[root@aliyun ~]# b=$(bc << EOF
> ibase=10;
> obase=2;
> $a
> EOF
> )
[root@aliyun ~]# echo $b
1100100

如果有大量的數學計算,那麼使用輸入重定向就比較方便,因為數學表示式可以換行,寫起來更加清晰。

2.流程控制語句

2.1 if else語句

if語法

多行寫法語法

if  條件
then
    命令
fi

可以將if語句放入一行語法

if 條件; then 命令; fi

if else 語法

if  條件
then
   命令
else
   命令
fi

if elif else 語法

if  條件1
then
   命令1
elif 條件2
then
    命令2
elif 條件3
then
    命令3
……
else
   命令N
fi

演示

#!/bin/bash
read -p "請輸入你的考試成績:" score
if (( $score < 60 )); then
    echo "不及格"
elif (( $score >= 60 && $score < 70 )); then
    echo "及格"
elif (( $score >= 70 && $score < 80 )); then
    echo "中等"
elif (( $score >= 80 && $score < 90 )); then
    echo "良好"
elif (( $score >= 90 && $score <= 100 )); then
    echo "優秀"
else
    echo "成績不合法"
fi

(())是一種數學計算命令,它除了可以進行最基本的加減乘除運算,還可以進行大於、小於、等於等關係運算,以及與、或、非邏輯運算。當 a 和 b 相等時,(( $a == $b ))判斷條件成立,進入 if,執行 then 後邊的 echo 語句

if條件判斷句的退出狀態

linux任何命令的的執行都會有一個退出狀態, 無論是內建命令還是外部檔案命令. 還是自定義的 Shell 函式,當它退出(執行結束)時,都會返回一個比較小的整數值給呼叫(使用)它的程式,這就是命令的退出狀態

大多數命令狀態0代表成功, 非0代表失敗. 也有特殊的命令,比如 diff 命令用來比較兩個檔案的不同,對於“沒有差別”的檔案返回 0,對於“找到差別”的檔案返回 1,對無效檔名返回 2

Shell 中,有多種方式取得命令的退出狀態,其中 $? 是最常見的一種.

abc@aliyun:/tmp/bgtest$ ((1==2))
abc@aliyun:/tmp/bgtest$ echo $?
1
abc@aliyun:/tmp/bgtest$ ((1==1))
abc@aliyun:/tmp/bgtest$ echo $?
0
abc@aliyun:/tmp/bgtest$ cd ..
abc@aliyun:/tmp$ echo $?
0

退出狀態和邏輯運算子的組合

Shell if 語句使用邏輯運算子將多個退出狀態組合起來,這樣就可以一次判斷多個條件了。

運算子 使用格式 說明
&& 或 -a 條件1 && 條件2 邏輯與運算子,當 條件1 和 條件2 同時成立時,
整個表示式才成立。 如果檢測到 條件1 的退出狀態為 0,
就不會再檢測 條件2 了,因為不管 條件2 的退出狀態是什麼,
整個表示式必然都是不成立的,檢測了也是多此一舉。
|| 或 -o 條件1 || 條件2 邏輯或運算子,條件1 和 條件2 兩個表
達式中只要有一個成立,整個表示式就成立。 如果檢
測到 條件1 的退出狀態為 1,就不會再檢測 條件2 了,因為
不管 條件2 的退出狀態是什麼,整個表示式必然都是成立的,
檢測了也是多此一舉。
! !條件 邏輯非運算子,相當於“取反”的效果。如果 條件 成立,那麼整
個表示式就不成立;如果 條件 不成立,那麼整個表示式就成立。

示例

提示輸入"請輸入檔案全名: "和"請輸入資料:" 並接收檔名與資料

使用邏輯運算子判斷滿足2 條件 : 檔案需要具有可寫許可權 和 輸入的資料長度不為0

滿足以上2個條件 將使用者輸入的 資料 寫入到指定的檔案中去

#!/bin/bash
read -p "請輸入檔案全名: " filename
read -p "請輸入資料:" data
if [ -w $filename -a -n $data ]
then
        echo $data
        echo $data > $filename
        echo "成功"
else
        echo "失敗"
fi

test命令用於對檔案或字串進行檢測, -w 判斷檔案是否存在並且可寫, -n 用於檢測字串是否非空

$data > $filename 其中 > 用於將內容輸出到指定檔案中去

Shell內建命令:test

Shell中的 test 命令用於檢查某個條件是否成立,它可以進行數值、字元和檔案三個方面的測試。

功能與[]一樣

整數比較測試

if test 數字1 options 數字2 
then  
...
fi

options具體如下

引數 說明
-eq 等於則為真
-ne 不等於則為真
-gt 大於則為真
-ge 大於等於則為真
-lt 小於則為真
-le 小於等於則為真

演示

#!/bin/bash
num1=1 num2=1 num3=2
echo "num1=${num1},num2=${num2},num3=${num3}"

if test $num1 -eq $num2
then
    echo 'num1和num2兩個數相等!'
else
    echo 'num1和num2兩個數不相等!'
fi

if test $num2 -eq $num3
then
    echo 'num2和num3兩個數相等!'
else
    echo 'num2和num3兩個數不相等!'
fi

字串比較測試

引數 說明
= 或 == 等於, 等於返回0代表成功,否則返回1代表失敗
!= 不等於
\< 小於
\> 大於
-z 字串 字串的長度為零則為真
-n 字串 字串的長度不為零則為真

演示

#!/bin/bash

str1="itheima" str2="itcast" str3=""
echo "str1=${str1},str2=${str2},str3=${str3}"

if test $str1 = $str2
then
    echo 'str1和str2兩個字串相等'
else
    echo 'str1和str2兩個字串不相等'
fi

if test $str1 \> $str2
then
    echo 'str1大於str2'
else
    echo 'str1小於str2'
fi

if test -z $str2
then
	echo "str2字串長度為0"
else
	echo "str2字串長度不為0"
fi

if test -z $str3
then
	echo "str3字串長度為0"
else
	echo "str3字串長度不為0"
fi

檔案測試

引數 說明
-e 檔名 exists, 如果檔案存在則為真
-r 檔名 read,如果檔案存在且可讀則為真
-w 檔名 write,如果檔案存在且可寫則為真
-x 檔名 execute,如果檔案存在且可執行則為真
-s 檔名 string,如果檔案存在且至少有一個字元則為真
-d 檔名 directory,如果檔案存在且為目錄則為真
-f 檔名 file,如果檔案存在且為普通檔案則為真
-c 檔名 character,如果檔案存在且為字元型特殊檔案則為真
-b 檔名 如果檔案存在且為塊特殊檔案則為真

演示

#!/bin/bash

if test -w ./control1.sh
then
    echo '檔案已存在並且可寫!'
else
    echo '檔案不存在或不可寫!'
fi

if test -e ./control1.sh -a -e ./control2.sh
then
    echo '兩個檔案都存在!'
else
    echo '可能有一個或兩個檔案不存在'
fi

Shell提供了與( -a )、或( -o )、非( ! )三個邏輯操作符用於將測試條件連線起來,其優先順序為:"!"最高,"-a"次之,"-o"最低, 語法

test 條件1 -o 條件2 -a 條件3 ...

2.2 case語句

Shell case語句為多選擇語句。可以用case語句匹配一個值與一個模式,如果匹配成功,執行相匹配的命令;

當分支較多,並且判斷條件比較簡單時,使用 case in 語句就比較方便了。

case 值 in
匹配模式1)
    命令1
    命令2
    ...
    ;;
匹配模式2)
    命令1
    命令2
    ...
    ;;
*)
    命令1
    命令2
    ...
    ;;
esac

每一匹配模式必須以右括號結束。取值可以為變數或常數。匹配發現取值符合某一模式後,其間所有命令開始執行直至 ;;(類似break, 不可以替代否則語法報錯)。取值將檢測匹配的每一個模式。一旦模式匹配,則執行完匹配模式相應命令後不再繼續其他模式。如果無一匹配模式,使用星號 * 捕獲該值,再執行後面的命令。

case、in 和 esac 都是 Shell 關鍵字, esac就是case的反寫在這裡代表結束case

匹配模式: 可以是一個數字、一個字串,甚至是一個簡單正則表示式。

簡單正則表示式支援如下萬用字元

格式 說明
* 表示任意字串。
[abc] 表示 a、b、c 三個字元中的任意一個。比如,[15ZH] 表示 1、5、Z、H 四個字元中的任意一個。
[m-n] 表示從 m 到 n 的任意一個字元。比如,[0-9] 表示任意一個數字,[0-9a-zA-Z] 表示字母或數字。
| 表示多重選擇,類似邏輯運算中的或運算。比如,abc | xyz 表示匹配字串 "abc" 或者 "xyz"。

演示

#!/bin/bash
read -p "請輸入一個0~7的數字:" number
case $number in
1)
    echo "星期一"
	;;
2)
    echo "星期二"
    ;;
3)
    echo "星期三"
    ;;
4)
    echo "星期四"
    ;;
5)
    echo "星期五"
    ;;
6)
    echo "星期六"
    ;;
0|7)
    echo "星期日"
    ;;
*)
    echo "您輸入的數字無效"
    ;; 
esac

2.3 while語句

while用於迴圈執行一系列命令

多行寫法

while 條件
do
	命令1
	命令2
	...
	continue; # 結束當前這一次迴圈, 進入下一次迴圈
	break; # 結束當前迴圈
done

一行寫法

while 條件; do 命令; done;

演示

#!/bin/bash
read -p "請輸入一個數字:" number
i=0
while [[ $i < $number ]]
do
  echo "hello world"
  ((i++))
done

無限迴圈

while :
do
    command
done

while true
do
    command
done

2.4 until語句

until 也是迴圈結構語句, until 迴圈與 while 迴圈在處理方式上剛好相反, 迴圈條件為false會一致迴圈, 條件為true停止迴圈.

until 條件
do
    命令
done

條件如果返回值為1(代表false),則繼續執行迴圈體內的語句,否則跳出迴圈。

演示

#!/bin/bash
read -p "請輸入一個數字:" number
i=0
until [[ ! $i < $number ]]
do
  echo "hello world"
  ((i++))
done

2.5 for語句

Shell支援for迴圈, 與其他程式語言類似.

迴圈方式1

多行寫法

for var in item1 item2 ... itemN
do
    命令1
    命令2
    ...
done

一行寫法

for var in item1 item2 ... itemN; do 命令1; 命令2…; done;

var是迴圈變數

item1 item2 ... itemN 是迴圈的範圍

演示

#!/bin/bash
for i in 1 2 3 4 5
do
 echo "hello world"
done

迴圈方式2

多行寫法

for var in {start..end}
do
	命令
done

start: 迴圈範圍的起始值,必須為整數

end: 迴圈範圍的結束值, 必須為整數

一行寫法

for var in {start..end}; do 命令; done

演示

迴圈1到5並列印

for i in {1..5}; do echo $i; done

迴圈方式3

多行寫法

for((i=start;i<=end;i++))
do
	命令
done

一行寫法

for((i=start;i<=end;i++)); do 命令; done

演示

abc@aliyun:~$ for ((i=1;i<=5;i++)); do echo "hello world ${i}"; done
hello world 1
hello world 2
hello world 3
hello world 4
hello world 5

無限迴圈

for((;;)); do 命令; done

2.6 流程控制:select語句

select in 迴圈用來增強互動性,它可以顯示出帶編號的選單,使用者輸入不同的編號就可以選擇不同的選單,並執行不同的功能. select in 是 Shell 獨有的一種迴圈,非常適合終端(Terminal)這樣的互動場景, 其他語言沒有;

select var in menu1 menu2 ...
do
    命令
done

注意: select 是無限迴圈(死迴圈),輸入空值,或者輸入的值無效,都不會結束迴圈,只有遇到 break 語句,或者按下 Ctrl+D 組合鍵才能結束迴圈。

執行命令過程中: 終端會輸出 #? 代表可以輸入選擇的選單編號

演示1

#!/bin/bash
echo "你的愛好是什麼?"
select hobby in "程式設計" "遊戲" "籃球" "游泳"
do
	echo $hobby
    break
done
echo "你的愛好是:${hobby}"

演示2

#!/bin/bash
echo "你的愛好是什麼"
select hobby in "程式設計" "遊戲" "籃球" "游泳"
do
    case $hobby in
        "程式設計")
            echo "程式設計,多敲程式碼"
            break
            ;;
        "遊戲")
            echo "少玩遊戲"
            break
            ;;
        "籃球"|"游泳")
            echo "運動有利健康"
            break
            ;;
        *)
            echo "輸入錯誤,請重新輸入"
    esac
done

3.Shell函式

函式分類

  1. 系統函式
  2. 自定義函式

3.1 系統函式

Shell程式設計和其他程式語言一樣, 有函式, 函式是由若干條shell命令組成的語句塊,實現Shell指令碼程式碼重用和模組化程式設計。

系統自帶提供的函式, 可以直接使用.

basename系統函式

basename函式用於獲取檔名的函式, 根據給出的檔案路徑截取出檔名

語法

basename [string / pathname] [suffix]  

根據根據指定字串或路徑名進行擷取檔名, 比如: 根據路徑"/one/two/aa.txt", 可以截取出aa.txt

suffix: 用於擷取的時候去掉指定的字尾名.

演示

abc@aliyun:/tmp$ basename ./aa.sh 					# 獲取指定路徑的檔名
aa.sh
abc@aliyun:/tmp$ basename ./aa.sh .sh					# 獲取檔名並去掉指定字尾
aa

dirname系統函式

從指定的檔案絕對路徑, 去除檔名,返回剩下的字首目錄路徑

dirname 檔案絕對路徑

3.2 自定義函式

開發人員可以通過自定義開發函式,實現程式碼重用.

# 函式的定義
[ function ] funname ()
{
    命令
    [return 返回值]

}

# 呼叫函式
funname 傳遞引數1 傳遞引數2 ...
  1. 可以帶function fun() 定義,也可以直接fun() 定義,不帶任何引數。

  2. 引數返回,可以顯示加:return 返回,如果不加,將以最後一條命令執行結果,作為返回值。 return後跟數值n(0~255)

注意

必須在呼叫函式地方之前,先宣告函式,shell指令碼是逐行執行, 只要先運行了函式, 後面才可以時使用函式

示例:無參無返回值函式

檔案指令碼程式碼

#!/bin/bash
demo()
{
    echo "執行了函式"
}

# 呼叫函式
demo

示例:無參有返回值函式

#!/bin/bash
sum()
{
    echo "求兩個數的和..."
    read -p "輸入第一個數字: " n1
    read -p "輸入第二個數字: " n2
    echo "兩個數字分別為 $n1 和 $n2 "
    return $(($n1+$n2))
}

# 呼叫函式
sum
echo "兩個數字的和為: $? "  # 獲取函式返回值

示例:有參函式

在Shell中,呼叫函式時可以向其傳遞引數。在函式體內部,通過 $n 的形式來獲取引數的值,例如,$1 表示第一個引數,$2 表示第二個引數...

其他引數介紹

引數處理 說明
$# 傳遞到指令碼或函式的引數個數
$* 以一個單字串顯示所有向指令碼傳遞的引數
$$ 指令碼執行的當前程序ID號
$! 後臺執行的最後一個程序的ID號
$@ 與$*相同,但是使用時加引號,並在引號中返回每個引數。
$? 顯示最後命令的退出狀態。0表示沒有錯誤,其他任何值表明有錯誤。

演示

#!/bin/bash
funParam(){
    echo "第一個引數為 $1 !"
    echo "第二個引數為 $2 !"
    echo "第十個引數為 $10 !"
    echo "第十個引數為 ${10} !"
    echo "第十一個引數為 ${11} !"
    echo "引數總數有 $# 個!"
    echo "作為一個字串輸出所有引數 $* !"
}
# 呼叫函式
funParam 1 2 3 4 5 6 7 8 9 10 22

Shell程式與函式的區別

函式和shell程式比較相似,區別在於:
Shell 程式(內建命令和外部指令碼檔案), 外部指令碼檔案是在子Shell中執行, 會開啟獨立的程序執行
Shell函式在當前Shell的程序中執行

演示

#!/bin/bash
demo(){
        echo "函式中列印當前程序ID:$$"
}

echo "當前指令碼檔案(Shell程式)列印當前程序ID:$$"
# 呼叫函式
demo

4.Shell重定向輸入輸出

4.1 重定向介紹

標準輸入介紹

從鍵盤讀取使用者輸入的資料,然後再把資料拿到Shell程式中使用;

標準輸出介紹

Shell程式產生的資料,這些資料一般都是呈現到顯示器上供使用者瀏覽檢視;

預設輸入輸出檔案

每個 Unix/Linux 命令執行時都會開啟三個檔案, 檔案如下

檔名 型別 檔案描述符(file description, fd) 功能
stdin (standard input)
標準輸入檔案
0 獲取鍵盤的輸入資料
stdout (standard output)
標準輸出檔案
1 將正確資料輸出到顯示器上
stderr (standard error)
標準錯誤輸出檔案
2 將錯誤資訊輸出到顯示器上

每個檔案都有一個唯一的 檔案描述符fd, 後面會通過唯一 檔案描述符fd 操作對應的資訊

Shell程式操作輸入輸出時用到這3個檔案

  1. Shell程式預設會從stdin檔案中讀取輸入資料
  2. Shell程式預設會向stdout檔案輸出正確資料
  3. Shell程式預設會項stderr檔案中輸出錯誤資訊

這3個檔案用於臨時傳輸資料使用

重定向輸入輸出介紹

  1. 標準輸入是資料預設從鍵盤流向程式,如果改變了它的方向,資料就從其它地方流入,這就是輸入重定向。

  2. 標準輸出是資料預設從程式流向顯示器,如果改變了它的方向,資料就流向其它地方,這就是輸出重定向。

    Linux Shell 重定向分為兩種,一種輸入重定向,一種是輸出重定向;

重定向的作用

輸出重定向是指命令的結果不再輸出到顯示器上,而是輸出到其它地方,一般是檔案中。這樣做的最大好處就是把命令的結果儲存起來,當我們需要的時候可以隨時查詢。

重定向語法

命令 說明
命令 > file 將正確資料重定向輸出到 file 檔案中, 覆蓋方式
命令 < file 將輸入重定向從 file 檔案中讀取資料
命令 >> file 將正確資料重定向輸出到 file 檔案中, 追加方式
命令 < file1 > file2 從file檔案讀取資料, 輸出資料到file2檔案中
命令 fd> file 根據指定的檔案描述符fd 將資料重定向輸出到 file 檔案中, 覆蓋方式
命令 fd>> file 根據指定的檔案描述符fd 將資料重定向輸出到 file 檔案中, 追加方式
命令 > file fd1>& fd2 將 fd1 和 fd2 檔案描述符合並 輸出到檔案。
fd1<& fd2 將 fd1 和 fd2 檔案描述符合並 從檔案讀取輸入.
<< tag 讀取終端輸入資料, 將開始標記 tag 和結束標記 tag 之間的內容作為輸入。
標記名tag可以任意

在輸出重定向中,>代表的是覆蓋輸出,>>代表的是追加輸出。

fd是檔案描述符

​ 0 通常是標準輸入(STDIN),

​ 1 是標準輸出(STDOUT),

​ 2 是標準錯誤輸出(STDERR)。

fd> 或 fd>> 中間不可以有空格

4.2 輸出輸入示例

輸出示例:正確資訊重定向輸出

建立檔案redirect1.txt

touch redirect1.txt

執行who命令重定向輸出到redirect1.txt檔案中

echo "itheima" >> redirect1.txt

輸出示例:錯誤資訊重定向輸出

預覽錯誤訊息

abc@aliyun:/tmp$ ls java
ls: cannot access 'java': No such file or directory

沒有java目錄所以報錯

將錯誤訊息輸出到error.log檔案中

ls java 2> redirect2.txt

2 是標準錯誤輸出(STDERR), 注意

> 覆蓋方式輸出

2> 注意fd與>符號之間不能有空格

輸出示例:正確和錯誤資訊同時輸出

將正確資訊與錯誤資訊都儲存到一個檔案中

echo "itcast" > redirect2.txt 2>&1

數字 1 代表正確輸出的結果輸出到檔案中
數字 2 代表錯誤結果輸出到檔案中

2>& 1 將正確和錯誤都輸出到檔案中. 2>& 中間不能有空格, 寫法有2種

​ 合併第一種寫法: 2>& 1

​ 合併第二種寫法: 2>&1

執行效果

abc@aliyun:/tmp$ echo "hahaha" > loggg.txt 2>&1
abc@aliyun:/tmp$ cat loggg.txt 
hahaha
abc@aliyun:/tmp$ ls java >> loggg.txt 2>&1
abc@aliyun:/tmp$ cat loggg.txt 
hahaha
ls: cannot access 'java': No such file or directory

輸入示例:統計檔案資料行數

Linux wc 命令可以用來對文字進行統計,包括單詞個數、行數、位元組數

wc  [options]  [檔名]

options有如下:

選項 含義
-c character, 統計位元組數
-w word, 統計單詞數
-l line, 統計行數

演示

統計檔案redirect2.txt中資料行數

wc -l < redirect2.txt

執行效果

abc@aliyun:/tmp$ wc -l < loggg.txt 
2

輸入示例:逐行讀取檔案資料

迴圈讀取檔案每一行資料

while read str; do echo $str; done < redirect2.txt

執行效果

abc@aliyun:/tmp$ while read str;do echo $str;done < loggg.txt 
hahaha
ls: cannot access 'java': No such file or directory

輸入示例:讀取終端輸入資料的行數

abc@aliyun:/tmp$ wc -l <<END
> aa
> bb
> cc
3
abc@aliyun:/tmp$