1. 程式人生 > >shell的結構化命令

shell的結構化命令

####shell在邏輯流程控制這裡會根據設定的變數值的條件或其他命令的結果跳過一些命令或者迴圈執行的這些命令。這些命令通常稱為結構化命令


1、if-then語句介紹

基本格式
if command
then
  commands
fi
在其他語言中if語句後的物件值為TRUE或FALSE的等式、bash shell指令碼中的if不是這樣的

[[email protected] sbin]# sh data.sh 
2018年 10月 04日 星期四 18:45:15 CST
echo it worked
[[email protected] sbin]# cat data.sh 
#!/bin/bash
if date
then
echo echo "it worked"
fi 

[
[email protected]
sbin]# sh data.sh data.sh:行2: data: 未找到命令 [[email protected] sbin]# cat data.sh #!/bin/bash if data ##修改後的 then echo echo "it worked" fi

bash shell中的if語句在if行定義的命令。如果命令的退出狀態是0(成功執行),將執行then後面的所有命令,如果命令的退出狀態是非0的,那麼then後面的命令將不會執行。 ($?命令的返回狀態) 0                命令成功結束 1              通用未知錯誤 2    誤用shell命令 126            命令不可執行 127            沒找到命令 128            無效退出引數 128+x        Linux 訊號x的嚴重錯誤 130            Linux 訊號2 的嚴重錯誤,即命令通過SIGINT(Ctrl+C)終止 255            退出狀態碼越界

另一種形式
if command;then
conmmands
fi

2、if-then-else語句 那麼相應的命名返回狀態為非0時,還需要執行一些需求時就需要多一種選擇 命令的結構式

if command ;then
  commands
else
  commands
fi

如果命令的返回狀態為非0時,bash shell會移步到指令碼的下一條命令。反之就會執行在then部分。

[[email protected] sbin]# cat grep1.sh grep.sh 
#!/bin/bash
user=nihao ##判斷存在的使用者
if grep $user /etc/passwd;then
	echo the files for user $user are:
else
	echo "the user name $user doesn't exist this system"
fi
#!/bin/bash
user=root ##判斷存在的使用者
if grep $user /etc/passwd;then
	echo the files for user $user are:
else
	echo "the user name $user doesn't exist this system"
fi
[
[email protected]
sbin]# [[email protected] sbin]# sh grep.sh root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin the files for user root are: [[email protected] sbin]# sh grep1.sh the user name nihao doesn't exist this system

3、巢狀if語句 有時在指令碼程式碼中需要檢查幾種情況。if-then-else滿足不了時,需要elif。

if command1;then
  commands
elif command2;then
  commands
elif command3;then
  commands
fi

像這種情況會按循序匹配command1/2/3的執行返回值,第一個返回0時的elif會執行then部分


4、test命令 if語句中除了執行普通的shell命令外,還有一個test命令。 test命令根據退出程式碼狀態,判斷條件執行條件為true或者false。

test的命令格式:
test condithon
condition是一系列test命令評估的引數和值。在if-then語句中使用時,命令格式:
if test condition;then
  commands
fi
或
if [ condition ];then
  commands
fi
方括號裡定義了test命令的使用條件。(在括號裡括號的開頭和結尾必須加一個空格,否則會報錯)

test命令能夠評估一下3類條件:
*數值比較
*字串比較
*檔案比較

4.1數值比較 數值比較.png

[[email protected] sbin]# sh contrast.sh 1 2
不相等
[[email protected] sbin]# sh contrast.sh 2 2
相等
[[email protected] sbin]# cat contrast.sh 
#!/bin/bash
if [ $1 -eq $2 ];then
echo 相等
else
echo 不相等
fi
[[email protected] sbin]# 
依次類推

在test命令中是不能夠傳浮點數的,命令中會報錯

[[email protected] sbin]# sh folt.sh 
3.333
folt.sh: 第 4 行:[: 3.333: 期待一元表示式
我們不一樣
[[email protected] sbin]# cat folt.sh 
#!/bin/bash
a=`echo "scale=3;10/3" |bc`
echo $a 
if [ $a >= 3 ];then
echo 一樣
else
echo 我們不一樣
fi

4.2字串比較 字串比較.png

等於判斷
[[email protected] sbin]# cat str.sh 
#!/bin/bash
if [ $1 = $2 ];then
echo 一樣
elif [ $1 != $2 ];then
echo 不一樣
fi
[[email protected] sbin]# sh str.sh aa aa
一樣
[[email protected] sbin]# sh str.sh aa bb
不一樣

字串比較長度是的大於或小於在shell中要特別注意倆點:
*大於和小於一定要轉義,否則shell會解釋成重定向符號,將字串看出檔名
*大於和小於順序於在sort命令中的順序不同

[[email protected] sbin]# sh str.sh thccc
大於
[[email protected] sbin]# sh str.sh thcc
不大於
[[email protected] sbin]# cat str.sh 
#!/bin/bash
a=thcc
if [ $1 \> $a ];then
echo 大於 
else 
echo 不大於
fi
[[email protected] sbin]# sh str.sh bb
大於
[[email protected] sbin]# sh str.sh bbaaa
大於
[[email protected] sbin]# sh str.sh bbaaaaaa
大於
[[email protected] sbin]# cat str.sh 
#!/bin/bash
a=thcc
if [ $1 > $a ];then ##要的結果變成了重定向
echo 大於 
else 
echo 不大於
fi  

4.3字串大小和檔案比較

字串比較
[[email protected] sbin]# cat len.sh 
#!/bin/bash
if [ -n $1 ];then
echo 長度大於零
else 
echo 空
fi

if [ -z $1 ];then
echo 空
else 
echo 長度大於零
fi
[[email protected] sbin]# sh len.sh nihao
長度大於零
長度大於零
[[email protected] sbin]# sh len.sh 
長度大於零
空

檔案比較
-d file 檢查檔案是否存在並且是目錄
-e file 檢查檔案是否存在
-f file 檢查問價是否存在並且是一個檔案
-r file 檢查檔案是否可讀
-s file 檢查檔案是否存在並且不為空
-w file 檢查檔案是否可寫
-x file 檢查檔案是否可執行
-O file 檢查檔案是否存在且被當前使用者擁有
-G file 檢查檔案是否存在且是當前使用者組
file1 -nt file2 檢查 檔案1是否比檔案2新
file1 -ot file2 檢查檔案1 是否比檔案2舊

*案例1 目錄物件檔案比較
[[email protected] sbin]# sh check.sh /etc/passwd
不是目錄
物件存在
是檔案
[[email protected] sbin]# cat check.sh 
#!/bin/bash
if [ -d $1 ];then
echo 是目錄
else
echo 不是目錄
fi
if [ -e $1 ];then
echo 物件存在
else
echo 物件不存在
fi

if [ -f $1 ];then
echo 是檔案
else
echo 不是檔案
fi  

*案例2 檔案屬組是否可讀比較
[[email protected] sbin]# sh check1.sh /etc/resolv.conf
檔案存在
檔案有可讀許可權
檔案是當前的使用者組
[[email protected] sbin]# cat check1.sh 
#!/bin/bash
if [ -f $1 ];then
echo 檔案存在
	if [ -r $1 ];then echo 檔案有可讀許可權;else null;fi
	if [ -G $1 ];then echo 檔案是當前的使用者組;else null;fi

else
echo 檔案不存在
fi
[[email protected] sbin]# ll -a /etc/resolv.conf
-rw-r--r--. 1 root root 53 10月  4 17:18 /etc/resolv.conf

*案例3 檔案或資料夾是否有資料查詢
[[email protected] sbin]# sh null.sh 
檔案或資料夾有資料
[[email protected] sbin]# sh null.sh kong.txt 
null
[[email protected] sbin]# cat null.sh 
#!/bin/bash
if [ -s $1 ];then
echo 檔案或資料夾有資料
else
echo null
fi

*案例4 檔案是否可寫可執行
[[email protected] sbin]# sh wr.sh /etc/passwd
可寫
null
[[email protected] sbin]# chmod u+x wr.sh 
[[email protected] sbin]# ./wr.sh wr.sh 
可寫
可執行
[[email protected] sbin]# ll -a wr.sh 
-rwxr--r--. 1 root root 118 10月  5 00:17 wr.sh
[[email protected] sbin]# cat wr.sh 
#!/bin/bash
if [ -w $1 ];then
echo 可寫
	if [ -x $1 ];then echo 可執行;else echo null;fi
else 
echo 不可寫
fi



5、複合條件檢查 在if-then中使用布林邏輯來合併檢查條件:

 and
*[ condition1 ]  && [ condition2 ]
 or
*[ condition1 ]  || [ condition2 ] 

*案例
[[email protected] sbin]# ./wr.sh wr.sh 
可寫可執行
[[email protected] sbin]# ./wr.sh /etc/passwd
可以或可執行或都沒有
[[email protected] sbin]# cat wr.sh 
if [ -w $1 ] && [ -x $1 ];then 
echo 可寫可執行
else
echo 可以或可執行或都沒有
fi 
[[email protected] sbin]# 

6、if-then的高階特徵

*雙圓括號表示數學表達數
*雙方括號表示高階字串處理函式
6.1雙圓括號命令符號
val++ 後自增、val--後自減、++val前自增、--val前自減、!邏輯否定、~取反、**取冪、<< 逐為左移、>> 逐位右移、&布林值與、|布林值或、&&邏輯與、||邏輯或
*案例
[[email protected] sbin]# sh towbrackets.sh 30
900
[[email protected] sbin]# sh towbrackets.sh 1
小於
[[email protected] sbin]# cat towbrackets.sh 
#!/bin/bash
if (( $1 ** 2 > 90));then
(( a = $1 ** 2 ))
echo $a
else 
echo 小於
fi

6.2使用雙方括號
格式
[[ expression ]]
雙括號裡用的expression使用在test命令中,給test命令帶來了一個功能叫:
模式匹配
在模式匹配中可以定義字串匹配的正則表示式

*案例
[[email protected] sbin]# sh user.sh 
是
[[email protected] sbin]# cat user.sh 
#!/bin/bash
if [[ $USER == ro* ]];then
echo 是
else
echo 不是
fi


7、case命令 語法:

case variable in 
pattern 1 | pattern2) commands;;
pattern 3) commands;;
*) commands;;
esac

在一組資料中找固定的值,這種情況就需要多次呼叫if-then-else語句,如下所示:

[[email protected] sbin]# sh userif.sh 
當前使用者是root
[[email protected] sbin]# cat userif.sh 
#!/bin/bash
if [ $USER == root ];then
echo 當前使用者是$USER  
elif [ $USER == bob ];then
echo 當前使用者是$USER
elif [ $USER == boc ];then
echo 當前使用者是$USER
else
echo 沒有這個使用者
fi 

像這種多次呼叫elif的語句可以用case命令簡寫:

[[email protected] sbin]# sh userif.sh 
root, bob, boc
是列表中的root
[[email protected] sbin]# cat userif.sh 
#!/bin/bash
list="root, bob, boc"
echo $list
case $USER in
root | bob | boc)
echo 是列表中的$USER;;
*)
echo 沒有列表中的使用者
esac
[[email protected] sbin]# 

8、for命令 表示式格式是:

for var in list
do 
  commands
done

這個命令是一種常見的程式設計命令。通常用來重複一系列命令,直到滿足一個特定的值或條件迭代結束。

8.1 讀取列表中的值 for命令的最基本的使用方法是通過for命令中定義的一列值來迭代

[[email protected] sbin]# sh list.sh 
next start nihao
next start wo
next start shi
next start shei
[[email protected] sbin]# cat list.sh 
#!/bin/bash
for i in nihao wo shi shei 
do
echo next start $i
done 
[[email protected] sbin]# 

8.2 讀取列表中的複雜值 I don't know if this'll work

[[email protected] sbin]# sh list.sh 
next start:I
next start:dont know if thisll
next start:work
[[email protected] sbin]# cat list.sh 
#!/bin/bash
for i in I don't know if this'll work  
do
echo next start:$i
done 

忽然發現在列表中出現了'號,然後出來的值順序發生了變化。
像這種情況有倆種解決辦法:
*使用轉義字元(反斜槓)來轉義單引號;
*使用雙引號來定義使用單引號的值。
案例
[[email protected] sbin]# sh list.sh 
next start:I
next start:dont know if thisll
next start:work
--------------------------------------------------------------------
next start:I
next start:don't
next start:know
next start:if
next start:this'll
next start:work
-------------------------------------------------------------------
next start:I don't know if this'll work
-------------------------------------------------------------------
next start:I
next start: don't
next start:know
next start:if
next start:this'll
next start:work
[[email protected] sbin]# cat list.sh 
#!/bin/bash
for i in I don't know if this'll work  
do
echo next start:$i
done 
echo --------------------------------------------------------------------
for i in I don\'t know if this\'ll work ##1  
do
echo next start:$i
done 
echo -------------------------------------------------------------------
for i in "I don't know if this'll work"  ##2
do
echo next start:$i
done 
echo -------------------------------------------------------------------

for i in "I" " don't" "know" "if" "this'll" "work"  ##2
do
echo next start:$i
done 

8.3 從變數讀取列表

[[email protected] sbin]# sh list1.sh 
Content viewed root;
Content viewed bob;
Content viewed gc;
Content viewed goc;
Content viewed admin;
Content viewed tccapache;
[[email protected] sbin]# cat list1.sh 
#!/bin/bash
list="root bob gc goc admin tcc"
list=$list"apache"
for i in $list 
do 
 echo "Content viewed $i;"
done

8.4 讀取命令中的值

[[email protected] sbin]# sh list2.sh 
Content viewed on user roo;
Content viewed on user apache;
Content viewed on user pas;
Content viewed on user bob;
Content viewed on user hz;
Content viewed on user gouzhi;
Content viewed on user wanghao;
[[email protected] sbin]# cat list2.sh 
#!/bin/bash
for i in `cat user.txt`
do
echo "Content viewed on user $i;"
done
[[email protected] sbin]# cat user.txt 
roo
apache
pas
bob
hz
gouzhi
wanghao

8.5 改變shell的欄位分割符 在預設情況下,bash shell 的預設分割符是:

*空格;
*製表符;
*換行符。

修改預設環境變數IFS的值,限制bash shell 看作是欄位分割字元的字元。

案例1
[[email protected] sbin]# sh list3.sh 
list this is user roo
list this is user apache
list this is user pas
list this is user bob
list this is user hz
list this is user gouzhi
list this is user wanghao
list this is user roo
apache
pas
bob
hz
gouzhi
wanghao
list this is user roo
apache
pas
bob
hz
gouzhi
wanghao
[[email protected] sbin]# cat user.txt 
roo
apache
pas
bob
hz
gouzhi
wanghao

由於user.txt檔案的格式使用的是換行符,所以只有限定IFS為換行符時執行了遍歷。
案例2
[ro[email protected] sbin]# sh test.sh 
root
x
0
0
root
/root
/bin/bash
bin
x
1
1
bin
/bin
/sbin/nologin
[[email protected] sbin]# cat test.sh 
#!/bin/bash
IFS=$'\n':  #限定多個分割符
for i in `cat /etc/passwd |head -n 2`
do echo $i 
done 

8.6 使用萬用字元讀取目錄 檔案通配是生成與指定萬用字元匹配的檔案或路徑名的過程

[[email protected] sbin]# cat wildcard.sh 
#!/bin/bash

for i in /var/log/*  
do
	if [ -d $i ];then
		echo 輸出目錄$i
	elif [ -f $i ];then
		echo 輸出檔案$i
	fi

done
[[email protected] sbin]# sh wildcard.sh 
輸出目錄/var/log/anaconda
輸出目錄/var/log/audit
輸出檔案/var/log/boot.log
輸出檔案/var/log/boot.log-20180626
輸出檔案/var/log/boot.log-20180627
輸出檔案/var/log/boot.log-20181004
輸出檔案/var/log/boot.log-20181006
輸出檔案/var/log/btmp
輸出檔案/var/log/btmp-20181003
輸出目錄/var/log/chrony
...

9.C式的for命令 9.1 C語言中的for命令

for (i = 0 ; i < 10 ; i ++)
{
printf ("The next number is %d\n" , i);
}
一個簡單的自增迭代式
[[email protected] sbin]# sh for.sh 
The next number is 0
The next number is 1
The next number is 2
The next number is 3
The next number is 4
The next number is 5
The next number is 6
The next number is 7
The next number is 8
The next number is 9
The next number is 10
The next number is 11
The next number is 12
The next number is 13
The next number is 14
The next number is 15
The next number is 16
The next number is 17
The next number is 18
The next number is 19
The next number is 20
[[email protected] sbin]# cat for.sh 
#!/bin/bash
for (( i=0; i <=20; i++ ))
do 
echo "The next number is $i"
done 

9.2 使用多個變數 c式的for命令同樣可以使用多個變數迭代:

[[email protected] sbin]# sh for.sh 
1 - 10
2 - 9
3 - 8
4 - 7
5 - 6
6 - 5
7 - 4
8 - 3
9 - 2
10 - 1
[[email protected] sbin]# cat for.sh 
#!/bin/bash
for (( i=1, b=10; i <= 10; i++, b-- ))
do 
	echo "$i - $b"
done 

10、while 命令 while命令的格式:

while test command
do 
  other command
done
案例
[[email protected] sbin]# sh while.sh 
10
9
8
7
6
5
4
3
2
1
[[email protected] sbin]# cat while.sh 
#!/bin/bash
number=10
while [ $number -gt 0 ]
do 
	echo $number
	number=$[ $number - 1 ]
done
[[email protected] sbin]# 

10.1 使用多個條測試命令

[[email protected] sbin]# sh while.sh 
10
9
8
7
6
5
[[email protected] sbin]# cat while.sh 
#!/bin/bash
number=10
while [ $number -gt 0 ] ##設定大於0
	[ $number -ge 5 ] ##設定大於等於5
do 
	echo $number
	number=$[ $number - 1 ]
done

*while命令允許在while語句行定義多條test命令。只有最後一條測試命令的退出狀態是用來決定迴圈是如何停止的。


11、until命令 這個命令測試的結果和while相反,只測試退出狀態為非0的情況,退出狀態為非0,迴圈停止。 until的命令格式:

until test commands
do
  other commands
done

案例
[[email protected] sbin]# sh -x until.sh 
+ a=100
+ '[' 100 -eq 0 ']'
+ echo 100
100
+ a=75
+ '[' 75 -eq 0 ']'
+ echo 75
75
+ a=50
+ '[' 50 -eq 0 ']'
+ echo 50
50
+ a=25
+ '[' 25 -eq 0 ']'
+ echo 25
25
+ a=0
+ '[' 0 -eq 0 ']'
[[email protected] sbin]# cat until.sh 
#!/bin/bash
a=100
until [ $a -eq 0 ]
do
echo $a
a=$[ $a - 25 ]
done

依次判斷直到a=0時退出迴圈

12、巢狀迴圈

while和for的巢狀
[[email protected] sbin]# sh while-for.sh 
Input 10
input sum的值10
input sum的值11
Input 9
input sum的值9
input sum的值10
Input 8
input sum的值8
input sum的值9
Input 7
input sum的值7
input sum的值8
Input 6
input sum的值6
...
[[email protected] sbin]# cat while-for.sh 
#!/bin/bash
a=10
while [ $a -ge 0 ]
do 
echo "Input $a"
	 for (( i = 0; $i < 2; i++ ))
	 	do
			sum=$[ $a + $i ]
			echo "input sum的值$sum"
		done

a=$[ $a - 1]
done
 

13、檔案資料的迴圈 這裡需要結合 *使用巢狀迴圈 *更改環境變數IFS

...
adm:x:3:4:adm:/var/adm:/sbi -
value-key: 
adm
value-key: x
value-key: 3
value-key: 4
value-key: adm
value-key: /var/adm
value-key: /sbi
Values in / -
value-key: /
Values in ologi -
value-key: ologi
[[email protected] sbin]# cat file.sh 
#!/bin/bash
#IFS.OLD=$IFS
IFS='\n'
for i in `cat /etc/passwd |head -n 4`
do
	echo "Values in $i -"
	IFS=:
	for z in $i
	do
		echo "value-key: $z"
	done
#IFS=$IFS.OLD
done

14、迴圈的控制 迴圈不一定執行完,對於迴圈的控制需要用到倆個命令: break命令: continue命令。 14.1 break命令 這個命令是跳出迴圈

[[email protected] sbin]# sh break.sh 
---------------5------------
[[email protected] sbin]# cat break.sh 
#!/bin/bash
for i in `seq 1 10`
do 
	if [ $i -eq 5 ];then 
		break	
	fi
done 
echo ---------------$i------------ 

##不加break,正常情況這個$i會輸出1-10
這個命令同樣適用於while和until迴圈

14.2 continue命令 跳出迴圈後繼續執行

[[email protected] sbin]# sh continue.sh 
----------------------1-------------------
----------------------2-------------------
----------------------3-------------------
----------------------4-------------------
----------------------6-------------------
----------------------7-------------------
----------------------8-------------------
----------------------9-------------------
----------------------11-------------------
----------------------12-------------------
----------------------13-------------------
----------------------14-------------------
----------------------15-------------------
----------------------16-------------------
----------------------17-------------------
----------------------18-------------------
----------------------19-------------------
----------------------20-------------------
[[email protected] sbin]# cat continue.sh 
#!/bin/bash
for i in `seq 1 20`
do 
	case $i in 
	5 )
		continue
	 ;; 
	10)
		continue
	 ;;
	esac

echo ----------------------$i-------------------

##這裡只是跳過了5和10
done  

15、處理迴圈的輸出 最後,可以在shell指令碼中使用管道或重定向的方式輸出結果。通過在done命令的末尾新增處理命令實現

*重定向
[[email protected] sbin]# cat output.txt 
輸出檔案--/home/all-in-one
輸出目錄--/home/hzy
輸出目錄--/home/kolla-ansible
輸出檔案--/home/multinode
[[email protected] sbin]# cat yy.sh 
#!/bin/bash
for i in /home/* 
do
if [ -d $i ];then
	echo "輸出目錄--$i"
	
elif [ -f $i ];then
	echo "輸出檔案--$i"
fi
done > output.txt

*管道符號
[[email protected] sbin]# sh sort.sh 
123-----------------
aFASDF-----------------
aff-----------------
asA-----------------
fsdf222-----------------
s2234-----------------
[[email protected] sbin]# cat sort.sh 
#!/bin/bash
for i in 123 aff s2234 asA aFASDF fsdf222
do
echo $i-----------------
done | sort

簡書連結


END