溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么用Bash編程實(shí)現(xiàn)循環(huán)

發(fā)布時(shí)間:2021-10-25 11:27:30 來(lái)源:億速云 閱讀:120 作者:小新 欄目:系統(tǒng)運(yùn)維

這篇文章主要介紹怎么用Bash編程實(shí)現(xiàn)循環(huán),文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!


循環(huán)

我使用過(guò)的所有編程語(yǔ)言都至少有兩種循環(huán)結(jié)構(gòu)來(lái)用來(lái)執(zhí)行重復(fù)的操作。我經(jīng)常使用 for 循環(huán),然而我發(fā)現(xiàn) whileuntil 循環(huán)也很有用處。

for 循環(huán)

我的理解是,在 bash 中實(shí)現(xiàn)的 for 命令比大部分語(yǔ)言靈活,因?yàn)樗梢蕴幚矸菙?shù)字的值;與之形成對(duì)比的是,諸如標(biāo)準(zhǔn) C 語(yǔ)言的 for 循環(huán)只能處理數(shù)字類(lèi)型的值。

Bash 版的 for 命令基本的結(jié)構(gòu)很簡(jiǎn)單:

for Var in list1 ; do list2 ; done

解釋一下:“對(duì)于 list1 中的每一個(gè)值,把 $Var 設(shè)置為那個(gè)值,使用該值執(zhí)行 list2 中的程序語(yǔ)句;list1 中的值都執(zhí)行完后,整個(gè)循環(huán)結(jié)束,退出循環(huán)?!?list1 中的值可以是一個(gè)簡(jiǎn)單的顯式字符串值,也可以是一個(gè)命令執(zhí)行后的結(jié)果(`` 包含其內(nèi)的命令執(zhí)行的結(jié)果,本系列第二篇文章中有描述)。我經(jīng)常使用這種結(jié)構(gòu)。

要測(cè)試它,確認(rèn) ~/testdir 仍然是當(dāng)前的工作目錄(PWD)。刪除目錄下所有東西,來(lái)看下這個(gè)顯式寫(xiě)出值列表的 for 循環(huán)的簡(jiǎn)單的示例。這個(gè)列表混合了字母和數(shù)字 — 但是不要忘了,在 bash 中所有的變量都是字符串或者可以被當(dāng)成字符串來(lái)處理。

[student@studentvm1 testdir]$ rm *[student@studentvm1 testdir]$ for I in a b c d 1 2 3 4 ; do echo $I ; doneabcd1234

給變量賦予更有意義的名字,變成前面版本的進(jìn)階版:

[student@studentvm1 testdir]$ for Dept in "Human Resources" Sales Finance "Information Technology" Engineering Administration Research ; do echo "Department $Dept" ; doneDepartment Human ResourcesDepartment SalesDepartment FinanceDepartment Information TechnologyDepartment EngineeringDepartment AdministrationDepartment Research

創(chuàng)建幾個(gè)目錄(創(chuàng)建時(shí)顯示一些處理信息):

[student@studentvm1 testdir]$ for Dept in "Human Resources" Sales Finance "Information Technology" Engineering Administration Research ; do echo "Working on Department $Dept" ; mkdir "$Dept"  ; doneWorking on Department Human ResourcesWorking on Department SalesWorking on Department FinanceWorking on Department Information TechnologyWorking on Department EngineeringWorking on Department AdministrationWorking on Department Research[student@studentvm1 testdir]$ lltotal 28drwxrwxr-x 2 student student 4096 Apr  8 15:45  Administrationdrwxrwxr-x 2 student student 4096 Apr  8 15:45  Engineeringdrwxrwxr-x 2 student student 4096 Apr  8 15:45  Financedrwxrwxr-x 2 student student 4096 Apr  8 15:45 'Human Resources'drwxrwxr-x 2 student student 4096 Apr  8 15:45 'Information Technology'drwxrwxr-x 2 student student 4096 Apr  8 15:45  Researchdrwxrwxr-x 2 student student 4096 Apr  8 15:45  Sales

mkdir 語(yǔ)句中 $Dept 變量必須用引號(hào)包裹起來(lái);否則名字中間有空格(如 Information Technology)會(huì)被當(dāng)做兩個(gè)獨(dú)立的目錄處理。我一直信奉的一條實(shí)踐規(guī)則:所有的文件和目錄都應(yīng)該為一個(gè)單詞(中間沒(méi)有空格)。雖然大部分現(xiàn)代的操作系統(tǒng)可以處理名字中間有空格的情況,但是系統(tǒng)管理員需要花費(fèi)額外的精力去確保腳本和  CLI 程序能正確處理這些特例。(即使它們很煩人,也務(wù)必考慮它們,因?yàn)槟阌肋h(yuǎn)不知道將擁有哪些文件。)

再次刪除 ~/testdir 下的所有東西 — 再運(yùn)行一次下面的命令:

[student@studentvm1 testdir]$ rm -rf * ; lltotal 0[student@studentvm1 testdir]$ for Dept in Human-Resources Sales Finance Information-Technology Engineering Administration Research ; do echo "Working on Department $Dept" ; mkdir "$Dept"  ; doneWorking on Department Human-ResourcesWorking on Department SalesWorking on Department FinanceWorking on Department Information-TechnologyWorking on Department EngineeringWorking on Department AdministrationWorking on Department Research[student@studentvm1 testdir]$ lltotal 28drwxrwxr-x 2 student student 4096 Apr  8 15:52 Administrationdrwxrwxr-x 2 student student 4096 Apr  8 15:52 Engineeringdrwxrwxr-x 2 student student 4096 Apr  8 15:52 Financedrwxrwxr-x 2 student student 4096 Apr  8 15:52 Human-Resourcesdrwxrwxr-x 2 student student 4096 Apr  8 15:52 Information-Technologydrwxrwxr-x 2 student student 4096 Apr  8 15:52 Researchdrwxrwxr-x 2 student student 4096 Apr  8 15:52 Sales

假設(shè)現(xiàn)在有個(gè)需求,需要列出一臺(tái) Linux 機(jī)器上所有的 RPM  包并對(duì)每個(gè)包附上簡(jiǎn)短的描述。我為北卡羅來(lái)納州工作的時(shí)候,曾經(jīng)遇到過(guò)這種需求。由于當(dāng)時(shí)開(kāi)源尚未得到州政府的“批準(zhǔn)”,而且我只在臺(tái)式機(jī)上使用  Linux,對(duì)技術(shù)一竅不通的老板(PHB)需要我列出我計(jì)算機(jī)上安裝的所有軟件,以便他們可以“批準(zhǔn)”一個(gè)特例。

你怎么實(shí)現(xiàn)它?有一種方法是,已知 rpm –qa 命令提供了 RPM 包的完整描述,包括了白癡老板想要的東西:軟件名稱(chēng)和概要描述。

讓我們一步步執(zhí)行出最后的結(jié)果。首先,列出所有的 RPM 包:

[student@studentvm1 testdir]$ rpm -qaperl-HTTP-Message-6.18-3.fc29.noarchperl-IO-1.39-427.fc29.x86_64perl-Math-Complex-1.59-429.fc29.noarchlua-5.3.5-2.fc29.x86_64java-11-openjdk-headless-11.0.ea.28-2.fc29.x86_64util-linux-2.32.1-1.fc29.x86_64libreport-fedora-2.9.7-1.fc29.x86_64rpcbind-1.2.5-0.fc29.x86_64libsss_sudo-2.0.0-5.fc29.x86_64libfontenc-1.1.3-9.fc29.x86_64<snip>

sortuniq 命令對(duì)列表進(jìn)行排序和打印去重后的結(jié)果(有些已安裝的 RPM 包具有相同的名字):

[student@studentvm1 testdir]$ rpm -qa | sort | uniqa2ps-4.14-39.fc29.x86_64aajohan-comfortaa-fonts-3.001-3.fc29.noarchabattis-cantarell-fonts-0.111-1.fc29.noarchabiword-3.0.2-13.fc29.x86_64abrt-2.11.0-1.fc29.x86_64abrt-addon-ccpp-2.11.0-1.fc29.x86_64abrt-addon-coredump-helper-2.11.0-1.fc29.x86_64abrt-addon-kerneloops-2.11.0-1.fc29.x86_64abrt-addon-pstoreoops-2.11.0-1.fc29.x86_64abrt-addon-vmcore-2.11.0-1.fc29.x86_64<snip>

以上命令得到了想要的 RPM 列表,因此你可以把這個(gè)列表作為一個(gè)循環(huán)的輸入信息,循環(huán)最終會(huì)打印每個(gè) RPM 包的詳細(xì)信息:

[student@studentvm1 testdir]$ for RPM in `rpm -qa | sort | uniq` ; do rpm -qi $RPM ; done

這段代碼產(chǎn)出了多余的信息。當(dāng)循環(huán)結(jié)束后,下一步就是提取出白癡老板需要的信息。因此,添加一個(gè) egrep 命令用來(lái)搜索匹配 ^Name^Summary 的行。脫字符(^)表示行首,整個(gè)命令表示顯示所有以 Name 或 Summary 開(kāi)頭的行。

[student@studentvm1 testdir]$ for RPM in `rpm -qa | sort | uniq` ; do rpm -qi $RPM ; done | egrep -i "^Name|^Summary"Name        : a2psSummary     : Converts text and other types of files to PostScriptName        : aajohan-comfortaa-fontsSummary     : Modern style true type fontName        : abattis-cantarell-fontsSummary     : Humanist sans serif fontName        : abiwordSummary     : Word processing programName        : abrtSummary     : Automatic bug detection and reporting tool<snip>

在上面的命令中你可以試試用 grep 代替 egrep ,你會(huì)發(fā)現(xiàn)用 grep 不能得到正確的結(jié)果。你也可以通過(guò)管道把命令結(jié)果用 less 過(guò)濾器來(lái)查看。最終命令像這樣:

[student@studentvm1 testdir]$ for RPM in `rpm -qa | sort | uniq` ; do rpm -qi $RPM ; done | egrep -i "^Name|^Summary" > RPM-summary.txt

這個(gè)命令行程序用到了管道、重定向和 for 循環(huán),這些全都在一行中。它把你的 CLI 程序的結(jié)果重定向到了一個(gè)文件,這個(gè)文件可以在郵件中使用或在其他地方作為輸入使用。

這個(gè)一次一步構(gòu)建程序的過(guò)程讓你能看到每步的結(jié)果,以此來(lái)確保整個(gè)程序以你期望的流程進(jìn)行且輸出你想要的結(jié)果。

白癡老板最終收到了超過(guò) 1900 個(gè)不同的 RPM 包的清單,我嚴(yán)重懷疑根本就沒(méi)人讀過(guò)這個(gè)列表。我給了他們想要的東西,沒(méi)有從他們嘴里聽(tīng)到過(guò)任何關(guān)于 RPM 包的信息。

其他循環(huán)

Bash 中還有兩種其他類(lèi)型的循環(huán)結(jié)構(gòu):whileuntil 結(jié)構(gòu),兩者在語(yǔ)法和功能上都類(lèi)似。這些循環(huán)結(jié)構(gòu)的基礎(chǔ)語(yǔ)法很簡(jiǎn)單:

while [ expression ] ; do list ; done

邏輯解釋?zhuān)罕磉_(dá)式(expression)結(jié)果為 true 時(shí),執(zhí)行程序語(yǔ)句 list。表達(dá)式結(jié)果為 false 時(shí),退出循環(huán)。

until [ expression ] ; do list ; done

邏輯解釋?zhuān)簣?zhí)行程序語(yǔ)句 list,直到表達(dá)式的結(jié)果為 true。當(dāng)表達(dá)式結(jié)果為 true 時(shí),退出循環(huán)。

While 循環(huán)

while 循環(huán)用于當(dāng)邏輯表達(dá)式結(jié)果為 true 時(shí)執(zhí)行一系列程序語(yǔ)句。假設(shè)你的 PWD 仍是 ~/testdir。

最簡(jiǎn)單的 while 循環(huán)形式是這個(gè)會(huì)一直運(yùn)行下去的循環(huán)。下面格式的條件語(yǔ)句永遠(yuǎn)以 true 作為返回。你也可以用簡(jiǎn)單的 1 代替 true,結(jié)果一樣,但是這解釋了 true 表達(dá)式的用法。

[student@studentvm1 testdir]$ X=0 ; while [ true ] ; do echo $X ; X=$((X+1)) ; done | head0123456789[student@studentvm1 testdir]$

既然你已經(jīng)學(xué)了 CLI 的各部分知識(shí),那就讓它變得更有用處。首先,為了防止變量 $X 在前面的程序或 CLI 命令執(zhí)行后有遺留的值,設(shè)置 $X 的值為 0。然后,因?yàn)檫壿嫳磉_(dá)式 [ true ] 的結(jié)果永遠(yuǎn)是 1,即 true,在 dodone 中間的程序指令列表會(huì)一直執(zhí)行 — 或者直到你按下 Ctrl+C 抑或發(fā)送一個(gè) 2 號(hào)信號(hào)給程序。那些程序指令是算數(shù)擴(kuò)展,用來(lái)打印變量 $X 當(dāng)前的值并加 1.

《系統(tǒng)管理員的 Linux 哲學(xué)》的信條之一是追求優(yōu)雅,實(shí)現(xiàn)優(yōu)雅的一種方式就是簡(jiǎn)化。你可以用操作符 ++ 來(lái)簡(jiǎn)化這個(gè)程序。在第一個(gè)例子中,變量當(dāng)前的值被打印出來(lái),然后變量的值增加了。可以在變量后加一個(gè) ++ 來(lái)表示這個(gè)邏輯:

[student@studentvm1 ~]$ X=0 ; while [ true ] ; do echo $((X++)) ; done | head0123456789

現(xiàn)在刪掉程序最后的 | head 再運(yùn)行一次。

在下面這個(gè)版本中,變量在值被打印之前就自增了。這是通過(guò)在變量之前添加 ++ 操作符實(shí)現(xiàn)的。你能看出區(qū)別嗎?

[student@studentvm1 ~]$ X=0 ; while [ true ] ; do echo $((++X)) ; done | head123456789

你已經(jīng)把打印變量的值和自增簡(jiǎn)化到了一條語(yǔ)句。類(lèi)似 ++ 操作符,也有 -- 操作符。

你需要一個(gè)在循環(huán)到某個(gè)特定數(shù)字時(shí)終止循環(huán)的方法。把 true 表達(dá)式換成一個(gè)數(shù)字比較表達(dá)式來(lái)實(shí)現(xiàn)它。這里有一個(gè)循環(huán)到 5 終止的程序。在下面的示例代碼中,你可以看到 -le 是 “小于或等于” 的數(shù)字邏輯操作符。整個(gè)語(yǔ)句的意思:只要 $X 的值小于或等于 5,循環(huán)就一直運(yùn)行。當(dāng) $X 增加到 6 時(shí),循環(huán)終止。

[student@studentvm1 ~]$ X=0 ; while [ $X -le 5 ] ; do echo $((X++)) ; done012345[student@studentvm1 ~]$
Until 循環(huán)

until 命令非常像 while 命令。不同之處是,它直到邏輯表達(dá)式的值是 true 之前,會(huì)一直循環(huán)。看一下這種結(jié)構(gòu)最簡(jiǎn)單的格式:

[student@studentvm1 ~]$ X=0 ; until false  ; do echo $((X++)) ; done | head0123456789[student@studentvm1 ~]$

它用一個(gè)邏輯比較表達(dá)式來(lái)計(jì)數(shù)到一個(gè)特定的值:

[student@studentvm1 ~]$ X=0 ; until [ $X -eq 5 ]  ; do echo $((X++)) ; done01234[student@studentvm1 ~]$ X=0 ; until [ $X -eq 5 ]  ; do echo $((++X)) ; done12345[student@studentvm1 ~]$

以上是“怎么用Bash編程實(shí)現(xiàn)循環(huán)”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI