導(dǎo)覽
- 在 shell 腳本中也可以使用
for、while循環(huán) -
until循環(huán)則是和while循環(huán)在條件判斷規(guī)則上完全相反的的一種循環(huán)操作 -
break命令支持直接終止循環(huán),同時(shí)還可以通過(guò)break n指定要終止的循環(huán)層級(jí) -
contiune命令支持直接中止當(dāng)前循環(huán),直接進(jìn)入下次循環(huán),同時(shí)還可以通過(guò)continue n指定要中止的循環(huán)層級(jí) - 在循環(huán)結(jié)束后可以再最后使用管道干預(yù)腳本的輸出結(jié)果,可以使用重定向?qū)⒛_本的輸出導(dǎo)入文件
13.1 for 命令
- 在 shell 中可以使用
for命令來(lái)循環(huán)遍歷一系列值,基本語(yǔ)法如下:- 使用效果和其他語(yǔ)法的 for 循環(huán)基本一致
for var in list
do
commands
done
13.1.1 讀取列表的值
-
for循環(huán)最基本的用法就是讀取列表的值,如下圖-
name 是在
for循環(huán)中聲明的局部變量,但是在循環(huán)結(jié)束后,該變量依舊可以正常被訪問(wèn),或者被修改
-
name 是在
[ttxie@41 part13]$ cat for-list.sh
#!/bin/bash
for name in ffjff fffoksfl kkkk lllll
do
echo "當(dāng)前的名字是${name}"
done
echo "最后名字是: ${name}"
name="newnames"
echo "當(dāng)前名字是: ${name}"

13.1.2 讀取列表中的復(fù)雜值
- 如果需要被遍歷的列表中的值存在一些復(fù)雜的組合,例如:?jiǎn)我?hào)、雙引號(hào)、空格
- 這個(gè)時(shí)候就需要先對(duì)這些特殊符號(hào)進(jìn)行轉(zhuǎn)義,方式有以下兩種
- 使用反斜線將單引號(hào)轉(zhuǎn)義
- 使用雙引號(hào)將用到單引號(hào)、空格的值進(jìn)行包裹
- 寫一個(gè)簡(jiǎn)單的例子演示一下,如下圖
-
需要注意的是,在第一個(gè)循環(huán)中的列表,連續(xù)使用了兩個(gè)沒(méi)有被轉(zhuǎn)義的單引號(hào),得到了如下的輸出結(jié)果,如果這里只使用了一個(gè)單引號(hào),例如
macbook's cpu is,造成的錯(cuò)誤將會(huì)更嚴(yán)重過(guò),會(huì)影響整個(gè) shell 腳本無(wú)法正常輸出結(jié)果image
-
13.1.3 從變量讀取列表
- 將需要被循環(huán)的列表存儲(chǔ)到變量中,再通過(guò)
for循環(huán)進(jìn)行遍歷輸出,會(huì)更美觀,如下圖- 變量不僅可以接受待輸出的列表值,還能對(duì)列表值進(jìn)行拼接
- 不過(guò)這種表現(xiàn)形式在其他語(yǔ)言中更像是字符串而已,不用介意,這就是 shell 的方式
[ttxie@41 part13]$ cat for-variable.sh
#!/bin/bash
names="asssss 1gkmgk 2jkmk"
names=$names" rys" ##追加字符串
for name in $names
do
echo "name: ${name}"
done

13.1.4 從命令讀取值
- 可以用命令替換來(lái)執(zhí)行任何可能產(chǎn)生輸出的命令,然后在
for循環(huán)的in關(guān)鍵字后使用該命令的輸出,如下圖- 變量 directory 存儲(chǔ)了一個(gè)目錄,然后再
for循環(huán)中使用$(ls $directory)輸出這個(gè)目錄的內(nèi)容
- 變量 directory 存儲(chǔ)了一個(gè)目錄,然后再
[ttxie@41 part13]$ cat for-command.sh
#!/bin/bash
for file in `ls $PWD`
do
echo "當(dāng)前目錄有的文件是: ${file}"
done
#-----------還可以這樣寫-----------
for file in $(ls $PWD)
do
echo "當(dāng)前目錄有的文件是: ${file}"
done
#------------遍歷文件中的字符-----------
for state in `cat for-variable.sh`
do
echo ${state}
done

13.1.5 更改字段分隔符
for循環(huán)之所以能將字符串的空格作為列表元素的分隔符,是因?yàn)橄到y(tǒng)中存在 內(nèi)部字段分隔符( Internal Field Separator ,IFS ) 的全局環(huán)境變量-
IFS 環(huán)境變量定義了 shell 作為字段分隔符的多個(gè)具體字符,默認(rèn)情況下,有以下幾種
- 空格
IFS=$'\ ' - 制表符
IFS=$'\t' - 換行符
IFS=$'\n'
- 空格
-
IFS 環(huán)境變量可以在 shell 腳本中進(jìn)行臨時(shí)修改,如下圖
- 下面這個(gè)例子中,將 IFS 的值改為只能識(shí)別換行符,所以就能順利的通過(guò)循環(huán)把每行的內(nèi)容輸出
[ttxie@41 part13]$ cat for-IFS.sh
#!/bin/bash
IFS=$'\n'
for line in $(cat $PWD/for-variable.sh)
do
echo ${line}
done

-
如果想要為 IFS 指定多個(gè)值,可以直接使用
IFS=$'\n':;"即可- 這就表示換行符、冒號(hào)、分號(hào)、雙引號(hào)都會(huì)被識(shí)別為字段分隔符
-
修改的IFS的值,只在腳本內(nèi)適用,不改變?nèi)肿兞俊?br> 有時(shí)候在一個(gè)大腳本中,有的地方需要修改IFS的值,然后忽略這次的修改,在腳本的其他地方繼續(xù)沿用IFS默認(rèn)值,可以這樣寫:
image.png
13.1.6 用通配符讀取目錄
- 在使用
for循環(huán)時(shí),就算不通過(guò)ls命令( 在 13.1.4 中有演示 )也能讀取目錄的內(nèi)容,使用 文件擴(kuò)展匹配 即可,如下圖- 其實(shí)就是在路徑最后使用通配符
[ttxie@41 part13]$ cat for-wildcards.sh
#!/bin/bash
dir="/BI/xtt/toolkits/shell/part13/*"
for file in ${dir}
do
if [ -d "$file" ]
then
echo "$file is a dir"
elif [ -f "$file" ]
then
echo "$file is a file"
fi
done

"$file" 加引號(hào) 是為了規(guī)避含有空格的文件名
- 在
for循環(huán)中還可以同時(shí)指定多個(gè)目錄,實(shí)現(xiàn)對(duì)輸出結(jié)果進(jìn)行拼接的效果,如下圖- 由于輸出的內(nèi)容太多,最后執(zhí)行的時(shí)候通過(guò)
| head命令只顯示了頭部的幾條信息
- 由于輸出的內(nèi)容太多,最后執(zhí)行的時(shí)候通過(guò)
[ttxie@41 part13]$ cat for-wildcards_plus.sh
#!/bin/bash
dir1="/BI/xtt/toolkits/shell/part13/*"
dir2="/BI/xtt/toolkits/shell/part12/*"
for file in ${dir1} ${dir2}
do
if [ -d "$file" ]
then
echo "$file is a dir"
elif [ -f "$file" ]
then
echo "$file is a file"
fi
done

13.2 C 語(yǔ)言風(fēng)格的 for 命令
13.2.1 C 語(yǔ)言的 for 命令
- 在 shell 中可以使用和 C 語(yǔ)言風(fēng)格類似的
for命令,基本語(yǔ)法如下
for (( variable assigment ; condition ; iteration process ))
do
commands
done
for (( a = 1 ; a < 10 ; a++ ))
do
echo "a : $a"
done
- 上述的
for命令語(yǔ)法在以下幾個(gè)方面沒(méi)有遵循 shell 標(biāo)準(zhǔn)- 變量賦值可以有空格
- 在條件中調(diào)用變量時(shí),不需要通過(guò)美元符號(hào)開(kāi)頭
- 迭代過(guò)程的算式不需要使用
expr命令
- 寫一個(gè)簡(jiǎn)單的例子演示一下,如下圖
[ttxie@41 part13]$ cat for-normal.sh
#!/bin/bash
for (( i=1; i<=10; i++ ))
do
echo $i
done

13.2.2 使用多個(gè)變量
- 在這種風(fēng)格的
for循環(huán)中,可以在條件中定義多個(gè)變量,如下圖- 可以看到,在變量定義時(shí),同時(shí)指定了變量 a 和 b ,并在最后規(guī)定了 a 和 b 的迭代方式
- 但需要注意的是,就算可以定義多個(gè)變量,但循環(huán)結(jié)束的條件只能有一個(gè)
[ttxie@41 part13]$ cat for-normal-plus.sh
#!/bin/bash
for (( a=1, b=10; a<=10; a++, b-- ))
do
echo "$a - $b"
done

13.3 while 命令
13.3.1 while 的基本格式
- 當(dāng) condition 返回非零的退出狀態(tài)碼時(shí),循環(huán)就會(huì)結(jié)束,否則循環(huán)將一直進(jìn)行
while [ condition ]
do
commands
done
- 寫一個(gè)簡(jiǎn)單的例子演示一下,如下圖
- 變量 num 初始值為 1
- 循環(huán)結(jié)束的條件是 num 小于 10
- 符合循環(huán)條件時(shí),num 每次都會(huì)在輸出后,累加 1 ,累加的方式是在第 12 章中學(xué)到的使用雙括號(hào)賦值
- 最后當(dāng) num 輸出到 9 時(shí),累加后等于 10 ,則無(wú)法再次循環(huán)
[ttxie@41 part13]$ cat while.sh
#!/bin/bash
n=1
while [ $n -lt 10 ]
do
echo "n的值:${n}"
(( n = ${n} + 1 ))
done

13.3.2 使用多個(gè)測(cè)試命令
-
while命令可以在條件語(yǔ)句中定義多個(gè)test命令,但只有最后一個(gè)命令會(huì)被作為 檢測(cè)循環(huán)是否結(jié)束 的條件,如下圖可以看到,在條件中定義了兩個(gè)測(cè)試命令,需要注意的是,每個(gè)測(cè)試命令都必須獨(dú)占一行
-
其他內(nèi)容都和上一個(gè) shell 腳本沒(méi)有區(qū)別,但是在輸出時(shí),最后會(huì)多輸出一個(gè) 10 ,這也就是
while命令支持多個(gè)測(cè)試命令的意義所在了image
13.4 until 命令
-
until命令的效果和while命令正好相反,但兩者的基本語(yǔ)法一致-
while命令是當(dāng)條件返回非零時(shí),就結(jié)束 -
until命令則是當(dāng)條件返回零時(shí),就結(jié)束
-
- 寫一個(gè)簡(jiǎn)單的例子演示一下,如下圖
可以看到,當(dāng)
until命令使用了和之前while命令一致的條件判斷時(shí),循環(huán)體根本無(wú)法進(jìn)入-
但當(dāng)使用了之前
while命令相反的條件判斷時(shí),循環(huán)體就順利進(jìn)入了image
13.5 嵌套循環(huán)
-
嵌套循環(huán)( Nested Loop ) 其實(shí)就是多個(gè)
for、while、until命令嵌套在一起- 被嵌套的叫 內(nèi)部循環(huán)( Inner Loop )
-
寫一個(gè)簡(jiǎn)單的例子演示一下,如下圖
image
13.6 循環(huán)處理文件數(shù)據(jù)
- 這個(gè)內(nèi)容其實(shí)在上文中的 13.1.5 更改字段分隔符 小節(jié)中就有演示
- 這里寫一個(gè)稍微復(fù)雜一點(diǎn)的升級(jí)版演示一下,如下圖
在讀取文件之前,將 IFS 的值改為了只識(shí)別換行符
在循環(huán)中輸出每行的內(nèi)容后,又將 IFS 的值改為只識(shí)別空格
-
這個(gè)時(shí)候?qū)⒚啃械臄?shù)據(jù)再次循環(huán),就可以得到每行的具體字符
image
13.7 控制循環(huán)
13.7.1 break 命令
- 在循環(huán)中使用
break命令可以直接退出循環(huán),在for、while、until中都可以使用
13.7.1.1 退出單個(gè)循環(huán)
- 可以看到,按照正常的循環(huán)邏輯,循環(huán)體應(yīng)該可以執(zhí)行 10 次,但是由于添加了當(dāng)值等于 5 時(shí)就執(zhí)行
break命令的條件判斷,所以在值等于 5 時(shí),循環(huán)就停止了
[ttxie@41 part13]$ cat for-break.sh
#!/bin/bash
for (( n=1; n<=10; n++ ))
do
echo "n的值為:$n"
if [ $n -eq 5 ]
then
break
fi
done

13.7.1.2 退出內(nèi)部循環(huán)
可以看到,本來(lái)外部循環(huán)可以執(zhí)行 5 次,并且在值小于 3 時(shí),每次外部循環(huán)執(zhí)行時(shí),內(nèi)部循環(huán)都可以執(zhí)行
-
但在第一次外部循環(huán)中,內(nèi)部循環(huán)執(zhí)行兩次后,就由于條件判斷被中斷了
image
13.7.1.3 從內(nèi)部循環(huán)直接退出外部循環(huán)
-
break命令支持使用break n指定循環(huán)的層級(jí),表示會(huì)直接退出 n 層的循環(huán)體,如下圖可以看到,shell 腳本的內(nèi)容和上一個(gè)例子基本一致,唯一的修改就是內(nèi)不循環(huán)的
break改成了break 2-
在執(zhí)行腳本后,之前內(nèi)部循環(huán)觸發(fā)
break后,這次造成的結(jié)果是整個(gè) shell 腳本的終止image
13.7.2 continue 命令
在循環(huán)中使用
continue命令可以直接中止當(dāng)前循環(huán),直接進(jìn)入下一次循環(huán),在for、while、until中都可以使用-
但是在
while和until中使用continue時(shí)需要注意,不能把continue放在迭代條件之前,否則就會(huì)造成無(wú)限循環(huán),如下圖原本
while循環(huán)的條件判斷是當(dāng) num 小于 5 時(shí),就一直循環(huán),每次循環(huán) num 都會(huì)加 1 ,所以一共會(huì)循環(huán) 5 次但是在 num 的累加操作
(( num = $num + 1 ))之前增加了一個(gè)當(dāng)num = 2時(shí)就continue的操作這就導(dǎo)致當(dāng) num 等于 2 時(shí),當(dāng)前循環(huán)就會(huì)被中止,直接進(jìn)入下一次循環(huán),而 num 的累加操作每次都沒(méi)有被執(zhí)行
-
最后就無(wú)限循環(huán)了
image
-
continue和break一樣,也可以通過(guò)指定層級(jí)來(lái)跳過(guò)對(duì)應(yīng)的層級(jí)的循環(huán),如下圖本來(lái)外部循環(huán)會(huì)循環(huán) 5 次,并且每次外部循環(huán)時(shí),內(nèi)部循環(huán)都會(huì)循環(huán) 5 次
-
但是由于
continue 2的加入,當(dāng)內(nèi)部循環(huán)的值等于 2 時(shí),外部循環(huán)也會(huì)被跳過(guò)image
13.8 處理循環(huán)的輸出
- 在循環(huán)的
done關(guān)鍵字之后可以使用管道或者重定向操作 - 結(jié)合管道的操作在 13.7.2 continue 命令 中已經(jīng)有演示,效果就是可以對(duì)腳本的輸出進(jìn)行干預(yù)
- 不過(guò)這個(gè)演示中是將管道放在了腳本執(zhí)行時(shí)
- 也可以將管道放在腳本內(nèi)部,
done關(guān)鍵字之后
- 結(jié)合重定向的操作則是可以將腳本的輸出重定向到文件中,如下圖
在循環(huán)結(jié)束后通過(guò)
> result將輸出結(jié)果重定向到 result 文件中可以看到,腳本執(zhí)行后終端沒(méi)有輸出任何語(yǔ)句
-
查看當(dāng)前目錄可以看到出現(xiàn)了一個(gè) result 的文件,里面的內(nèi)容就是剛才執(zhí)行腳本的輸出內(nèi)容
image
13.9 實(shí)例
13.9.1 查找可執(zhí)行的文件
掃描PATH環(huán)境變量中可執(zhí)行的文件:
[ttxie@41 part13]$ cat find-read.sh
#!/bin/bash
IFS=:
for folder in $PATH
do
echo "folder: $folder"
for file in $folder/*
do
if [ -x $file ]
then
echo " $file"
fi
done
done

部分內(nèi)容轉(zhuǎn)載來(lái)自:
作者:asing1elife
鏈接:http://www.itdecent.cn/p/b1522b99711a
來(lái)源:簡(jiǎn)書(shū)
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。










