自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

怎樣用Bash編程:循環(huán)

系統(tǒng) Linux
本文是 Bash 編程系列三篇中的最后一篇,來學習使用循環(huán)執(zhí)行迭代的操作。Bash 是一種強大的用于命令行和 shell 腳本的編程語言。本系列的三部分都是基于我的三集 Linux 自學課程 寫的,探索怎么用 CLI 進行 bash 編程。

怎樣用Bash編程:循環(huán)

本文是 Bash 編程系列三篇中的最后一篇,來學習使用循環(huán)執(zhí)行迭代的操作。

Bash 是一種強大的用于命令行和 shell 腳本的編程語言。本系列的三部分都是基于我的三集 Linux 自學課程 寫的,探索怎么用 CLI 進行 bash 編程。

本系列的 第一篇文章 討論了 bash 編程的一些簡單命令行操作,如使用變量和控制操作符。第二篇文章 探討了文件、字符串、數(shù)字等類型和各種各樣在執(zhí)行流中提供控制邏輯的的邏輯運算符,還有 bash 中不同種類的擴展。本文是第三篇(也是最后一篇),意在考察在各種迭代的操作中使用循環(huán)以及怎么合理控制循環(huán)。

循環(huán)

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

for 循環(huán)

我的理解是,在 bash 中實現(xiàn)的 for 命令比大部分語言靈活,因為它可以處理非數(shù)字的值;與之形成對比的是,諸如標準 C 語言的 for 循環(huán)只能處理數(shù)字類型的值。

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

  1. for Var in list1 ; do list2 ; done

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

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

  1. [student@studentvm1 testdir]$ rm *
  2. [student@studentvm1 testdir]$ for I in a b c d 1 2 3 4 ; do echo $I ; done
  3. a
  4. b
  5. c
  6. d
  7. 1
  8. 2
  9. 3
  10. 4

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

  1. [student@studentvm1 testdir]$ for Dept in "Human Resources" Sales Finance "Information Technology" Engineering Administration Research ; do echo "Department $Dept" ; done
  2. Department Human Resources
  3. Department Sales
  4. Department Finance
  5. Department Information Technology
  6. Department Engineering
  7. Department Administration
  8. Department Research

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

  1. [student@studentvm1 testdir]$ for Dept in "Human Resources" Sales Finance "Information Technology" Engineering Administration Research ; do echo "Working on Department $Dept" ; mkdir "$Dept"  ; done
  2. Working on Department Human Resources
  3. Working on Department Sales
  4. Working on Department Finance
  5. Working on Department Information Technology
  6. Working on Department Engineering
  7. Working on Department Administration
  8. Working on Department Research
  9. [student@studentvm1 testdir]$ ll
  10. total 28
  11. drwxrwxr-x 2 student student 4096 Apr  8 15:45  Administration
  12. drwxrwxr-x 2 student student 4096 Apr  8 15:45  Engineering
  13. drwxrwxr-x 2 student student 4096 Apr  8 15:45  Finance
  14. drwxrwxr-x 2 student student 4096 Apr  8 15:45 'Human Resources'
  15. drwxrwxr-x 2 student student 4096 Apr  8 15:45 'Information Technology'
  16. drwxrwxr-x 2 student student 4096 Apr  8 15:45  Research
  17. drwxrwxr-x 2 student student 4096 Apr  8 15:45  Sales

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

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

  1. [student@studentvm1 testdir]$ rm -rf * ; ll
  2. total 0
  3. [student@studentvm1 testdir]$ for Dept in Human-Resources Sales Finance Information-Technology Engineering Administration Research ; do echo "Working on Department $Dept" ; mkdir "$Dept"  ; done
  4. Working on Department Human-Resources
  5. Working on Department Sales
  6. Working on Department Finance
  7. Working on Department Information-Technology
  8. Working on Department Engineering
  9. Working on Department Administration
  10. Working on Department Research
  11. [student@studentvm1 testdir]$ ll
  12. total 28
  13. drwxrwxr-x 2 student student 4096 Apr  8 15:52 Administration
  14. drwxrwxr-x 2 student student 4096 Apr  8 15:52 Engineering
  15. drwxrwxr-x 2 student student 4096 Apr  8 15:52 Finance
  16. drwxrwxr-x 2 student student 4096 Apr  8 15:52 Human-Resources
  17. drwxrwxr-x 2 student student 4096 Apr  8 15:52 Information-Technology
  18. drwxrwxr-x 2 student student 4096 Apr  8 15:52 Research
  19. drwxrwxr-x 2 student student 4096 Apr  8 15:52 Sales

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

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

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

  1. [student@studentvm1 testdir]$ rpm -qa
  2. perl-HTTP-Message-6.18-3.fc29.noarch
  3. perl-IO-1.39-427.fc29.x86_64
  4. perl-Math-Complex-1.59-429.fc29.noarch
  5. lua-5.3.5-2.fc29.x86_64
  6. java-11-openjdk-headless-11.0.ea.28-2.fc29.x86_64
  7. util-linux-2.32.1-1.fc29.x86_64
  8. libreport-fedora-2.9.7-1.fc29.x86_64
  9. rpcbind-1.2.5-0.fc29.x86_64
  10. libsss_sudo-2.0.0-5.fc29.x86_64
  11. libfontenc-1.1.3-9.fc29.x86_64
  12. <snip>

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

  1. [student@studentvm1 testdir]$ rpm -qa | sort | uniq
  2. a2ps-4.14-39.fc29.x86_64
  3. aajohan-comfortaa-fonts-3.001-3.fc29.noarch
  4. abattis-cantarell-fonts-0.111-1.fc29.noarch
  5. abiword-3.0.2-13.fc29.x86_64
  6. abrt-2.11.0-1.fc29.x86_64
  7. abrt-addon-ccpp-2.11.0-1.fc29.x86_64
  8. abrt-addon-coredump-helper-2.11.0-1.fc29.x86_64
  9. abrt-addon-kerneloops-2.11.0-1.fc29.x86_64
  10. abrt-addon-pstoreoops-2.11.0-1.fc29.x86_64
  11. abrt-addon-vmcore-2.11.0-1.fc29.x86_64
  12. <snip>

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

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

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

  1. [student@studentvm1 testdir]$ for RPM in `rpm -qa | sort | uniq` ; do rpm -qi $RPM ; done | egrep -i "^Name|^Summary"
  2. Name        : a2ps
  3. Summary     : Converts text and other types of files to PostScript
  4. Name        : aajohan-comfortaa-fonts
  5. Summary     : Modern style true type font
  6. Name        : abattis-cantarell-fonts
  7. Summary     : Humanist sans serif font
  8. Name        : abiword
  9. Summary     : Word processing program
  10. Name        : abrt
  11. Summary     : Automatic bug detection and reporting tool
  12. <snip>

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

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

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

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

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

其他循環(huán)

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

  1. while [ expression ] ; do list ; done

邏輯解釋:表達式(expression)結(jié)果為 true 時,執(zhí)行程序語句 list。表達式結(jié)果為 false 時,退出循環(huán)。

  1. until [ expression ] ; do list ; done

邏輯解釋:執(zhí)行程序語句 list,直到表達式的結(jié)果為 true。當表達式結(jié)果為 true 時,退出循環(huán)。

While 循環(huán)

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

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

  1. [student@studentvm1 testdir]$ X=0 ; while [ true ] ; do echo $X ; X=$((X+1)) ; done | head
  2. 0
  3. 1
  4. 2
  5. 3
  6. 4
  7. 5
  8. 6
  9. 7
  10. 8
  11. 9
  12. [student@studentvm1 testdir]$

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

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

  1. [student@studentvm1 ~]$ X=0 ; while [ true ] ; do echo $((X++)) ; done | head
  2. 0
  3. 1
  4. 2
  5. 3
  6. 4
  7. 5
  8. 6
  9. 7
  10. 8
  11. 9

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

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

  1. [student@studentvm1 ~]$ X=0 ; while [ true ] ; do echo $((++X)) ; done | head
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5
  7. 6
  8. 7
  9. 8
  10. 9

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

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

  1. [student@studentvm1 ~]$ X=0 ; while [ $X -le 5 ] ; do echo $((X++)) ; done
  2. 0
  3. 1
  4. 2
  5. 3
  6. 4
  7. 5
  8. [student@studentvm1 ~]$

Until 循環(huán)

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

  1. [student@studentvm1 ~]$ X=0 ; until false  ; do echo $((X++)) ; done | head
  2. 0
  3. 1
  4. 2
  5. 3
  6. 4
  7. 5
  8. 6
  9. 7
  10. 8
  11. 9
  12. [student@studentvm1 ~]$

它用一個邏輯比較表達式來計數(shù)到一個特定的值:

  1. [student@studentvm1 ~]$ X=0 ; until [ $X -eq 5 ]  ; do echo $((X++)) ; done
  2. 0
  3. 1
  4. 2
  5. 3
  6. 4
  7. [student@studentvm1 ~]$ X=0 ; until [ $X -eq 5 ]  ; do echo $((++X)) ; done
  8. 1
  9. 2
  10. 3
  11. 4
  12. 5
  13. [student@studentvm1 ~]$

總結(jié)

本系列探討了構(gòu)建 Bash 命令行程序和 shell 腳本的很多強大的工具。但是這僅僅是你能用 Bash 做的很多有意思的事中的冰山一角,接下來就看你的了。

我發(fā)現(xiàn)學習 Bash 編程最好的方法就是實踐。找一個需要多個 Bash 命令的簡單項目然后寫一個 CLI 程序。系統(tǒng)管理員們要做很多適合 CLI 編程的工作,因此我確信你很容易能找到自動化的任務。

很多年前,盡管我對其他的 Shell 語言和 Perl 很熟悉,但還是決定用 Bash 做所有系統(tǒng)管理員的自動化任務。我發(fā)現(xiàn),有時稍微搜索一下,我可以用 Bash 實現(xiàn)我需要的所有事情。 

責任編輯:龐桂玉 來源: Linux中國
相關(guān)推薦

2019-11-08 15:10:59

BashBash編程Linux

2019-12-18 09:45:24

BashshellLinux

2019-11-20 12:30:21

Python編程語言語音識別

2018-04-11 09:30:16

Linux硬盤分區(qū)parted

2013-02-26 10:05:16

vmwareAWSOpenStack

2016-12-22 10:44:30

數(shù)據(jù)分析找對象大數(shù)據(jù)

2009-12-02 16:08:51

linux系統(tǒng)

2013-04-08 10:54:51

Javascript

2009-06-01 09:34:22

2011-01-21 13:41:09

Sendmail

2015-08-27 10:02:59

2010-04-16 10:38:49

CPU消耗

2009-11-26 17:03:24

Open Suse打印

2010-08-26 10:42:29

ADSL ModemDHCP服務器

2014-03-06 14:39:58

2022-03-07 09:20:00

JavaScripThree.jsNFT

2021-03-27 10:53:05

NodeJSCPU服務器

2014-06-20 09:27:27

BAT移動互聯(lián)網(wǎng)

2016-11-11 20:54:37

2011-07-25 14:08:49

ODP.NETOracle實體數(shù)據(jù)模型
點贊
收藏

51CTO技術(shù)棧公眾號