溫馨提示×

溫馨提示×

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

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

如何用Bash編程

發(fā)布時間:2021-10-25 11:27:07 來源:億速云 閱讀:172 作者:小新 欄目:系統(tǒng)運維

這篇文章將為大家詳細講解有關(guān)如何用Bash編程,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。



Shell 是操作系統(tǒng)的命令解釋器,其中 Bash 是我最喜歡的。每當用戶或者系統(tǒng)管理員將命令輸入系統(tǒng)的時候,Linux 的 shell  解釋器就會把這些命令轉(zhuǎn)換成操作系統(tǒng)可以理解的形式。而執(zhí)行結(jié)果返回 shell 程序后,它會將結(jié)果輸出到  STDOUT(標準輸出),默認情況下,這些結(jié)果會顯示在你的終端。所有我熟悉的 shell 同時也是一門編程語言。

Bash 是個功能強大的 shell,包含眾多便捷特性,比如:tab 補全、命令回溯和再編輯、別名等。它的命令行默認編輯模式是 Emacs,但是我最喜歡的 Bash 特性之一是我可以將其更改為 Vi 模式,以使用那些儲存在我肌肉記憶中的的編輯命令。

然而,如果你把 Bash 當作單純的 shell 來用,則無法體驗它的真實能力。我在設(shè)計一套包含三卷的 Linux 自學(xué)課程時(這個系列的文章正是基于此課程),了解到許多  Bash 的知識,這些是我在過去 20 年的 Linux 工作經(jīng)驗中所沒有掌握的,其中的一些知識就是關(guān)于 Bash  的編程用法。不得不說,Bash 是一門強大的編程語言,是一個能夠同時用于命令行和 shell 腳本的完美設(shè)計。

本系列文章將要探討如何使用 Bash 作為命令行界面(CLI)編程語言。第一篇文章簡單介紹 Bash  命令行編程、變量以及控制運算符。其他文章會討論諸如:Bash  文件的類型;字符串、數(shù)字和一些邏輯運算符,它們能夠提供代碼執(zhí)行流程中的邏輯控制;不同類型的 shell 擴展;通過 for、whileuntil 來控制循環(huán)操作。

Shell

Bash 是 Bourne Again Shell 的縮寫,因為 Bash shell 是 基于 更早的 Bourne shell,后者是 Steven Bourne 在 1977 年開發(fā)的。另外還有很多其他的 shell 可以使用,但下面四個是我經(jīng)常見到的:

  • csh:C shell 適合那些習(xí)慣了 C 語言語法的開發(fā)者。

  • ksh:Korn shell,由 David Korn 開發(fā),在 Unix 用戶中更流行。

  • tcsh:一個 csh 的變種,增加了一些易用性。

  • zsh:Z shell,集成了許多其他流行 shell 的特性。

所有 shell 都有內(nèi)置命令,用以補充或替代核心工具集。打開 shell 的 man 說明頁,找到“BUILT-INS”那一段,可以查看都有哪些內(nèi)置命令。

每種 shell 都有它自己的特性和語法風(fēng)格。我用過 csh、ksh 和 zsh,但我還是更喜歡 Bash。你可以多試幾個,尋找更適合你的 shell,盡管這可能需要花些功夫。但幸運的是,切換不同 shell 很簡單。

所有這些 shell 既是編程語言又是命令解釋器。下面我們來快速瀏覽一下 Bash 中集成的編程結(jié)構(gòu)和工具。

作為編程語言的 Bash

大多數(shù)場景下,系統(tǒng)管理員都會使用 Bash 來發(fā)送簡單明了的命令。但 Bash 不僅可以輸入單條命令,很多系統(tǒng)管理員可以編寫簡單的命令行程序來執(zhí)行一系列任務(wù),這些程序可以作為通用工具,能節(jié)省時間和精力。

編寫 CLI 程序的目的是要提高效率(做一個“懶惰的”系統(tǒng)管理員)。在 CLI 程序中,你可以用特定順序列出若干命令,逐條執(zhí)行。這樣你就不用盯著顯示屏,等待一條命令執(zhí)行完,再輸入另一條,省下來的時間就可以去做其他事情了。

什么是“程序”?

自由在線計算機詞典(FOLDOC)對于程序的定義是:“由計算機執(zhí)行的指令,而不是運行它們的物理硬件?!逼樟炙诡D大學(xué)的 WordNet 將程序定義為:“……計算機可以理解并執(zhí)行的一系列指令……”維基百科上也有一條不錯的關(guān)于計算機程序的條目。

總結(jié)下,程序由一條或多條指令組成,目的是完成一個具體的相關(guān)任務(wù)。對于系統(tǒng)管理員而言,一段程序通常由一系列的 shell  命令構(gòu)成。Linux 下所有的 shell (至少我所熟知的)都有基本的編程功能,Bash 作為大多數(shù) linux 發(fā)行版的默認  shell,也不例外。

本系列用 Bash 舉例(因為它無處不在),假如你使用一個不同的 shell 也沒關(guān)系,盡管結(jié)構(gòu)和語法有所不同,但編程思想是相通的。有些  shell 支持某種特性而其他 shell 則不支持,但它們都提供編程功能。Shell  程序可以被存在一個文件中被反復(fù)使用,或者在需要的時候才創(chuàng)建它們。

簡單 CLI 程序

最簡單的命令行程序只有一或兩條語句,它們可能相關(guān),也可能無關(guān),在按回車鍵之前被輸入到命令行。程序中的第二條語句(如果有的話)可能取決于第一條語句的操作,但也不是必須的。

這里需要特別講解一個標點符號。當你在命令行輸入一條命令,按下回車鍵的時候,其實在命令的末尾有一個隱含的分號(;)。當一段 CLI shell 程序在命令行中被串起來作為單行指令使用時,必須使用分號來終結(jié)每個語句并將其與下一條語句分開。但 CLI shell 程序中的最后一條語句可以使用顯式或隱式的分號。

一些基本語法

下面的例子會闡明這一語法規(guī)則。這段程序由單條命令組成,還有一個顯式的終止符:

[student@studentvm1 ~]$ echo "Hello world." ;Hello world.

看起來不像一個程序,但它確是我學(xué)習(xí)每個新編程語言時寫下的第一個程序。不同語言可能語法不同,但輸出結(jié)果是一樣的。

讓我們擴展一下這段微不足道卻又無所不在的代碼。你的結(jié)果可能與我的有所不同,因為我的家目錄有點亂,而你可能是在 GUI 桌面中第一次登錄賬號。

[student@studentvm1 ~]$ echo "My home directory." ; ls ;My home directory.chapter25   TestFile1.Linux  dmesg2.txt  Downloads  newfile.txt  softlink1  testdir6chapter26   TestFile1.mac    dmesg3.txt  file005    Pictures     Templates  testdirTestFile1      Desktop       dmesg.txt   link3      Public       testdir    VideosTestFile1.dos  dmesg1.txt    Documents   Music      random.txt   testdir1

現(xiàn)在是不是更明顯了。結(jié)果是相關(guān)的,但是兩條語句彼此獨立。你可能注意到我喜歡在分號前后多輸入一個空格,這樣會讓代碼的可讀性更好。讓我們再運行一遍這段程序,這次不要帶結(jié)尾的分號:

[student@studentvm1 ~]$ echo "My home directory." ; ls

輸出結(jié)果沒有區(qū)別。

關(guān)于變量

像所有其他編程語言一樣,Bash 支持變量。變量是個象征性的名字,它指向內(nèi)存中的某個位置,那里存著對應(yīng)的值。變量的值是可以改變的,所以它叫“變~量”。

Bash 不像 C 之類的語言,需要強制指定變量類型,比如:整型、浮點型或字符型。在 Bash 中,所有變量都是字符串。整數(shù)型的變量可以被用于整數(shù)運算,這是 Bash 唯一能夠處理的數(shù)學(xué)類型。更復(fù)雜的運算則需要借助 bc 這樣的命令,可以被用在命令行編程或者腳本中。

變量的值是被預(yù)先分配好的,這些值可以用在命令行編程或者腳本中??梢酝ㄟ^變量名字給其賦值,但是不能使用 $ 符開頭。比如,VAR=10 這樣會把 VAR 的值設(shè)為 10。要打印變量的值,你可以使用語句 echo $VAR。變量名必須以文本(即非數(shù)字)開始。

Bash 會保存已經(jīng)定義好的變量,直到它們被取消掉。

下面這個例子,在變量被賦值前,它的值是空(null)。然后給它賦值并打印出來,檢驗一下。你可以在同一行 CLI 程序里完成它:

[student@studentvm1 ~]$ echo $MyVar ; MyVar="Hello World" ; echo $MyVar ; Hello World[student@studentvm1 ~]$

注意:變量賦值的語法非常嚴格,等號(=)兩邊不能有空格。

那個空行表明了 MyVar 的初始值為空。變量的賦值和改值方法都一樣,這個例子展示了原始值和新的值。

正如之前說的,Bash 支持整數(shù)運算,當你想計算一個數(shù)組中的某個元素的位置,或者做些簡單的算術(shù)運算,這還是挺有幫助的。然而,這種方法并不適合科學(xué)計算,或是某些需要小數(shù)運算的場景,比如財務(wù)統(tǒng)計。這些場景有其它更好的工具可以應(yīng)對。

下面是個簡單的算術(shù)題:

[student@studentvm1 ~]$ Var1="7" ; Var2="9" ; echo "Result = $((Var1*Var2))"Result = 63

好像沒啥問題,但如果運算結(jié)果是浮點數(shù)會發(fā)生什么呢?

[student@studentvm1 ~]$ Var1="7" ; Var2="9" ; echo "Result = $((Var1/Var2))"Result = 0[student@studentvm1 ~]$ Var1="7" ; Var2="9" ; echo "Result = $((Var2/Var1))"Result = 1[student@studentvm1 ~]$

結(jié)果會被取整。請注意運算被包含在 echo 語句之中,其實計算在 echo 命令結(jié)束前就已經(jīng)完成了,原因是 Bash 的內(nèi)部優(yōu)先級。想要了解詳情的話,可以在 Bash 的 man 頁面中搜索 “precedence”。

控制運算符

Shell 的控制運算符是一種語法運算符,可以輕松地創(chuàng)建一些有趣的命令行程序。在命令行上按順序?qū)讉€命令串在一起,就變成了最簡單的 CLI 程序:

command1 ; command2 ; command3 ; command4 ; . . . ; etc. ;

只要不出錯,這些命令都能順利執(zhí)行。但假如出錯了怎么辦?你可以預(yù)設(shè)好應(yīng)對出錯的辦法,這就要用到 Bash 內(nèi)置的控制運算符, &&||。這兩種運算符提供了流程控制功能,使你能改變代碼執(zhí)行的順序。分號也可以被看做是一種 Bash 運算符,預(yù)示著新一行的開始。

&& 運算符提供了如下簡單邏輯,“如果 command1 執(zhí)行成功,那么接著執(zhí)行 command2。如果 command1 失敗,就跳過 command2?!闭Z法如下:

command1 && command2

現(xiàn)在,讓我們用命令來創(chuàng)建一個新的目錄,如果成功的話,就把它切換為當前目錄。確保你的家目錄(~)是當前目錄,先嘗試在 /root 目錄下創(chuàng)建,你應(yīng)該沒有權(quán)限:

[student@studentvm1 ~]$ Dir=/root/testdir ; mkdir $Dir/ && cd $Dirmkdir: cannot create directory '/root/testdir/': Permission denied[student@studentvm1 ~]$

上面的報錯信息是由 mkdir 命令拋出的,因為創(chuàng)建目錄失敗了。&& 運算符收到了非零的返回碼,所以 cd 命令就被跳過,前者阻止后者繼續(xù)運行,因為創(chuàng)建目錄失敗了。這種控制流程可以阻止后面的錯誤累積,避免引發(fā)更嚴重的問題。是時候講點更復(fù)雜的邏輯了。

當一段程序的返回碼大于零時,使用 || 運算符可以讓你在后面接著執(zhí)行另一段程序。簡單語法如下:

command1 || command2

解讀一下,“假如 command1 失敗,執(zhí)行 command2”。隱藏的邏輯是,如果 command1 成功,跳過 command2。下面實踐一下,仍然是創(chuàng)建新目錄:

[student@studentvm1 ~]$ Dir=/root/testdir ; mkdir $Dir || echo "$Dir was not created."mkdir: cannot create directory '/root/testdir': Permission denied/root/testdir was not created.[student@studentvm1 ~]$

正如預(yù)期,因為目錄無法創(chuàng)建,第一條命令失敗了,于是第二條命令被執(zhí)行。

&&|| 兩種運算符結(jié)合起來才能發(fā)揮它們的最大功效。請看下面例子中的流程控制方法:

前置 commands ; command1 && command2 || command3 ; 跟隨 commands

語法解釋:“假如 command1 退出時返回碼為零,就執(zhí)行 command2,否則執(zhí)行 command3。”用具體代碼試試:

[student@studentvm1 ~]$ Dir=/root/testdir ; mkdir $Dir && cd $Dir || echo "$Dir was not created."mkdir: cannot create directory '/root/testdir': Permission denied/root/testdir was not created.[student@studentvm1 ~]$

現(xiàn)在我們再試一次,用你的家目錄替換 /root 目錄,你將會有權(quán)限創(chuàng)建這個目錄了:

[student@studentvm1 ~]$ Dir=~/testdir ; mkdir $Dir && cd $Dir || echo "$Dir was not created."[student@studentvm1 testdir]$

command1 && command2 這樣的控制語句能夠運行的原因是,每條命令執(zhí)行完畢時都會給 shell 發(fā)送一個返回碼,用來表示它執(zhí)行成功與否。默認情況下,返回碼為 0 表示成功,其他任何正值表示失敗。一些系統(tǒng)管理員使用的工具用值為 1 的返回碼來表示失敗,但其他很多程序使用別的數(shù)字來表示失敗。

Bash 的內(nèi)置變量 $? 可以顯示上一條命令的返回碼,可以在腳本或者命令行中非常方便地檢查它。要查看返回碼,讓我們從運行一條簡單的命令開始,返回碼的結(jié)果總是上一條命令給出的。

[student@studentvm1 testdir]$ ll ; echo "RC = $?"total 1264drwxrwxr-x  2 student student   4096 Mar  2 08:21 chapter25drwxrwxr-x  2 student student   4096 Mar 21 15:27 chapter26-rwxr-xr-x  1 student student     92 Mar 20 15:53 TestFile1drwxrwxr-x. 2 student student 663552 Feb 21 14:12 testdirdrwxr-xr-x. 2 student student   4096 Dec 22 13:15 VideosRC = 0[student@studentvm1 testdir]$

在這個例子中,返回碼為零,意味著命令執(zhí)行成功了?,F(xiàn)在對 root 的家目錄測試一下,你應(yīng)該沒有權(quán)限:

[student@studentvm1 testdir]$ ll /root ; echo "RC = $?"ls: cannot open directory '/root': Permission deniedRC = 2[student@studentvm1 testdir]$

本例中返回碼是 2,表明非 root 用戶沒有權(quán)限進入這個目錄。你可以利用這些返回碼,用控制運算符來改變程序執(zhí)行的順序。

關(guān)于“如何用Bash編程”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節(jié)

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

AI