本篇文章為大家展示了Bash的語(yǔ)法和工具都有哪些,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。
十余年的豐寧網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開(kāi)發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。成都營(yíng)銷(xiāo)網(wǎng)站建設(shè)的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整豐寧建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無(wú)論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)建站從事“豐寧網(wǎng)站設(shè)計(jì)”,“豐寧網(wǎng)站推廣”以來(lái),每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。
Shell 是操作系統(tǒng)的 命令解釋器,其中 Bash 是我最喜歡的。每當(dāng)用戶或者系統(tǒng)管理員將 命令輸入系統(tǒng)的時(shí)候, Linux 的 shell 解釋器就會(huì)把這些命令轉(zhuǎn)換成操作系統(tǒng)可以理解的形式。而執(zhí)行結(jié)果返回 shell 程序后,它會(huì)將結(jié)果輸出到 STDOUT(標(biāo)準(zhǔn)輸出),默認(rèn)情況下,這些結(jié)果會(huì)顯示在你的終端。所有我熟悉的 shell 同時(shí)也是一門(mén)編程語(yǔ)言。 |
Bash 是個(gè)功能強(qiáng)大的 shell,包含眾多便捷特性,比如:tab 補(bǔ)全、命令回溯和再編輯、別名等。它的命令行默認(rèn)編輯模式是 Emacs,但是我最喜歡的 Bash 特性之一是我可以將其更改為 Vi 模式,以使用那些儲(chǔ)存在我肌肉記憶中的的編輯命令。
然而,如果你把 Bash 當(dāng)作單純的 shell 來(lái)用,則無(wú)法體驗(yàn)它的真實(shí)能力。我在設(shè)計(jì)一套包含三卷的 Linux 自學(xué)課程時(shí)(這個(gè)系列的文章正是基于此課程),了解到許多 Bash 的知識(shí),這些是我在過(guò)去 20 年的 Linux 工作經(jīng)驗(yàn)中所沒(méi)有掌握的,其中的一些知識(shí)就是關(guān)于 Bash 的編程用法。不得不說(shuō),Bash 是一門(mén)強(qiáng)大的編程語(yǔ)言,是一個(gè)能夠同時(shí)用于命令行和 shell 腳本的完美設(shè)計(jì)。
Shell
Bash 是 Bourne Again Shell 的縮寫(xiě),因?yàn)?Bash shell 是 基于 更早的 Bourne shell,后者是 Steven Bourne 在 1977 年開(kāi)發(fā)的。另外還有很多其他的 shell 可以使用,但下面四個(gè)是我經(jīng)常見(jiàn)到的:
csh:C shell 適合那些習(xí)慣了 C 語(yǔ)言語(yǔ)法的開(kāi)發(fā)者。
ksh:Korn shell,由 David Korn 開(kāi)發(fā),在 Unix 用戶中更流行。
tcsh:一個(gè) csh 的變種,增加了一些易用性。
zsh:Z shell,集成了許多其他流行 shell 的特性。
所有 shell 都有內(nèi)置命令,用以補(bǔ)充或替代核心工具集。打開(kāi) shell 的 man 說(shuō)明頁(yè),找到“BUILT-INS”那一段,可以查看都有哪些內(nèi)置命令。
每種 shell 都有它自己的特性和語(yǔ)法風(fēng)格。我用過(guò) csh、ksh 和 zsh,但我還是更喜歡 Bash。你可以多試幾個(gè),尋找更適合你的 shell,盡管這可能需要花些功夫。但幸運(yùn)的是,切換不同 shell 很簡(jiǎn)單。
所有這些 shell 既是編程語(yǔ)言又是命令解釋器。下面我們來(lái)快速瀏覽一下 Bash 中集成的編程結(jié)構(gòu)和工具。
作為編程語(yǔ)言的 Bash
大多數(shù)場(chǎng)景下,系統(tǒng)管理員都會(huì)使用 Bash 來(lái)發(fā)送簡(jiǎn)單明了的命令。但 Bash 不僅可以輸入單條命令,很多系統(tǒng)管理員可以編寫(xiě)簡(jiǎn)單的命令行程序來(lái)執(zhí)行一系列任務(wù),這些程序可以作為通用工具,能節(jié)省時(shí)間和精力。
編寫(xiě) CLI 程序的目的是要提高效率(做一個(gè)“懶惰的”系統(tǒng)管理員)。在 CLI 程序中,你可以用特定順序列出若干命令,逐條執(zhí)行。這樣你就不用盯著顯示屏,等待一條命令執(zhí)行完,再輸入另一條,省下來(lái)的時(shí)間就可以去做其他事情了。
什么是“程序”?
自由在線計(jì)算機(jī)詞典(FOLDOC)對(duì)于程序的定義是:“由計(jì)算機(jī)執(zhí)行的指令,而不是運(yùn)行它們的物理硬件?!逼樟炙诡D大學(xué)的 WordNet 將程序定義為:“……計(jì)算機(jī)可以理解并執(zhí)行的一系列指令……”維基百科上也有一條不錯(cuò)的關(guān)于計(jì)算機(jī)程序的條目。
總結(jié)下,程序由一條或多條指令組成,目的是完成一個(gè)具體的相關(guān)任務(wù)。對(duì)于系統(tǒng)管理員而言,一段程序通常由一系列的 shell 命令構(gòu)成。Linux 下所有的 shell (至少我所熟知的)都有基本的編程功能,Bash 作為大多數(shù) linux 發(fā)行版的默認(rèn) shell,也不例外。
本系列用 Bash 舉例(因?yàn)樗鼰o(wú)處不在),假如你使用一個(gè)不同的 shell 也沒(méi)關(guān)系,盡管結(jié)構(gòu)和語(yǔ)法有所不同,但編程思想是相通的。有些 shell 支持某種特性而其他 shell 則不支持,但它們都提供編程功能。Shell 程序可以被存在一個(gè)文件中被反復(fù)使用,或者在需要的時(shí)候才創(chuàng)建它們。
簡(jiǎn)單 CLI 程序
最簡(jiǎn)單的命令行程序只有一或兩條語(yǔ)句,它們可能相關(guān),也可能無(wú)關(guān),在按回車(chē)鍵之前被輸入到命令行。程序中的第二條語(yǔ)句(如果有的話)可能取決于第一條語(yǔ)句的操作,但也不是必須的。
這里需要特別講解一個(gè)標(biāo)點(diǎn)符號(hào)。當(dāng)你在命令行輸入一條命令,按下回車(chē)鍵的時(shí)候,其實(shí)在命令的末尾有一個(gè)隱含的分號(hào)(;)。當(dāng)一段 CLI shell 程序在命令行中被串起來(lái)作為單行指令使用時(shí),必須使用分號(hào)來(lái)終結(jié)每個(gè)語(yǔ)句并將其與下一條語(yǔ)句分開(kāi)。但 CLI shell 程序中的最后一條語(yǔ)句可以使用顯式或隱式的分號(hào)。
一些基本語(yǔ)法
下面的例子會(huì)闡明這一語(yǔ)法規(guī)則。這段程序由單條命令組成,還有一個(gè)顯式的終止符:
[student@studentvm1 ~]$ echo "Hello world." ; Hello world.
看起來(lái)不像一個(gè)程序,但它確是我學(xué)習(xí)每個(gè)新編程語(yǔ)言時(shí)寫(xiě)下的第一個(gè)程序。不同語(yǔ)言可能語(yǔ)法不同,但輸出結(jié)果是一樣的。
讓我們擴(kuò)展一下這段微不足道卻又無(wú)所不在的代碼。你的結(jié)果可能與我的有所不同,因?yàn)槲业募夷夸浻悬c(diǎn)亂,而你可能是在 GUI 桌面中第一次登錄賬號(hào)。
[student@studentvm1 ~]$ echo "My home directory." ; ls ; My home directory. chapter25 TestFile1.Linux dmesg2.txt Downloads newfile.txt softlink1 testdir6 chapter26 TestFile1.mac dmesg3.txt file005 Pictures Templates testdir TestFile1 Desktop dmesg.txt link3 Public testdir Videos TestFile1.dos dmesg1.txt Documents Music random.txt testdir1
現(xiàn)在是不是更明顯了。結(jié)果是相關(guān)的,但是兩條語(yǔ)句彼此獨(dú)立。你可能注意到我喜歡在分號(hào)前后多輸入一個(gè)空格,這樣會(huì)讓代碼的可讀性更好。讓我們?cè)龠\(yùn)行一遍這段程序,這次不要帶結(jié)尾的分號(hào):
[student@studentvm1 ~]$ echo "My home directory." ; ls
輸出結(jié)果沒(méi)有區(qū)別。
關(guān)于變量
像所有其他編程語(yǔ)言一樣,Bash 支持變量。變量是個(gè)象征性的名字,它指向內(nèi)存中的某個(gè)位置,那里存著對(duì)應(yīng)的值。變量的值是可以改變的,所以它叫“變~量”。
Bash 不像 C 之類(lèi)的語(yǔ)言,需要強(qiáng)制指定變量類(lèi)型,比如:整型、浮點(diǎn)型或字符型。在 Bash 中,所有變量都是字符串。整數(shù)型的變量可以被用于整數(shù)運(yùn)算,這是 Bash 唯一能夠處理的數(shù)學(xué)類(lèi)型。更復(fù)雜的運(yùn)算則需要借助 bc 這樣的命令,可以被用在命令行編程或者 腳本中。
變量的值是被預(yù)先分配好的,這些值可以用在命令行編程或者腳本中??梢酝ㄟ^(guò)變量名字給其賦值,但是不能使用 $ 符開(kāi)頭。比如,VAR=10 這樣會(huì)把 VAR 的值設(shè)為 10。要打印變量的值,你可以使用語(yǔ)句 echo $VAR。變量名必須以文本(即非數(shù)字)開(kāi)始。
Bash 會(huì)保存已經(jīng)定義好的變量,直到它們被取消掉。
下面這個(gè)例子,在變量被賦值前,它的值是空(null)。然后給它賦值并打印出來(lái),檢驗(yàn)一下。你可以在同一行 CLI 程序里完成它:
[student@studentvm1 ~]$ echo $MyVar ; MyVar="Hello World" ; echo $MyVar ; Hello World [student@studentvm1 ~]$
注意:變量賦值的語(yǔ)法非常嚴(yán)格,等號(hào)(=)兩邊不能有空格。
那個(gè)空行表明了 MyVar 的初始值為空。變量的賦值和改值方法都一樣,這個(gè)例子展示了原始值和新的值。
正如之前說(shuō)的,Bash 支持整數(shù)運(yùn)算,當(dāng)你想計(jì)算一個(gè)數(shù)組中的某個(gè)元素的位置,或者做些簡(jiǎn)單的算術(shù)運(yùn)算,這還是挺有幫助的。然而,這種方法并不適合科學(xué)計(jì)算,或是某些需要小數(shù)運(yùn)算的場(chǎng)景,比如財(cái)務(wù)統(tǒng)計(jì)。這些場(chǎng)景有其它更好的工具可以應(yīng)對(duì)。
下面是個(gè)簡(jiǎn)單的算術(shù)題:
[student@studentvm1 ~]$ Var1="7" ; Var2="9" ; echo "Result = $((Var1*Var2))" Result = 63
好像沒(méi)啥問(wèn)題,但如果運(yùn)算結(jié)果是浮點(diǎn)數(shù)會(huì)發(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é)果會(huì)被取整。請(qǐng)注意運(yùn)算被包含在 echo 語(yǔ)句之中,其實(shí)計(jì)算在 echo 命令結(jié)束前就已經(jīng)完成了,原因是 Bash 的內(nèi)部?jī)?yōu)先級(jí)。想要了解詳情的話,可以在 Bash 的 man 頁(yè)面中搜索 “precedence”。
控制運(yùn)算符
Shell 的控制運(yùn)算符是一種語(yǔ)法運(yùn)算符,可以輕松地創(chuàng)建一些有趣的命令行程序。在命令行上按順序?qū)讉€(gè)命令串在一起,就變成了最簡(jiǎn)單的 CLI 程序:
command1 ; command2 ; command3 ; command4 ; . . . ; etc. ;
只要不出錯(cuò),這些命令都能順利執(zhí)行。但假如出錯(cuò)了怎么辦?你可以預(yù)設(shè)好應(yīng)對(duì)出錯(cuò)的辦法,這就要用到 Bash 內(nèi)置的控制運(yùn)算符, && 和 ||。這兩種運(yùn)算符提供了流程控制功能,使你能改變代碼執(zhí)行的順序。分號(hào)也可以被看做是一種 Bash 運(yùn)算符,預(yù)示著新一行的開(kāi)始。
&& 運(yùn)算符提供了如下簡(jiǎn)單邏輯,“如果 command1 執(zhí)行成功,那么接著執(zhí)行 command2。如果 command1 失敗,就跳過(guò) command2?!闭Z(yǔ)法如下:
command1 && command2
現(xiàn)在,讓我們用命令來(lái)創(chuàng)建一個(gè)新的目錄,如果成功的話,就把它切換為當(dāng)前目錄。確保你的家目錄(~)是當(dāng)前目錄,先嘗試在 /root 目錄下創(chuàng)建,你應(yīng)該沒(méi)有權(quán)限:
[student@studentvm1 ~]$ Dir=/root/testdir ; mkdir $Dir/ && cd $Dir mkdir: cannot create directory '/root/testdir/': Permission denied [student@studentvm1 ~]$
上面的報(bào)錯(cuò)信息是由 mkdir 命令拋出的,因?yàn)閯?chuàng)建目錄失敗了。&& 運(yùn)算符收到了非零的返回碼,所以 cd 命令就被跳過(guò),前者阻止后者繼續(xù)運(yùn)行,因?yàn)閯?chuàng)建目錄失敗了。這種控制流程可以阻止后面的錯(cuò)誤累積,避免引發(fā)更嚴(yán)重的問(wèn)題。是時(shí)候講點(diǎn)更復(fù)雜的邏輯了。
當(dāng)一段程序的返回碼大于零時(shí),使用 || 運(yùn)算符可以讓你在后面接著執(zhí)行另一段程序。簡(jiǎn)單語(yǔ)法如下:
command1 || command2
解讀一下,“假如 command1 失敗,執(zhí)行 command2”。隱藏的邏輯是,如果 command1 成功,跳過(guò) command2。下面實(shí)踐一下,仍然是創(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ù)期,因?yàn)槟夸洘o(wú)法創(chuàng)建,第一條命令失敗了,于是第二條命令被執(zhí)行。
把 && 和 || 兩種運(yùn)算符結(jié)合起來(lái)才能發(fā)揮它們的最大功效。請(qǐng)看下面例子中的流程控制方法:
前置 commands ; command1 && command2 || command3 ; 跟隨 commands
語(yǔ)法解釋:“假如 command1 退出時(shí)返回碼為零,就執(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)在我們?cè)僭囈淮?,用你的家目錄替換 /root 目錄,你將會(huì)有權(quán)限創(chuàng)建這個(gè)目錄了:
[student@studentvm1 ~]$ Dir=~/testdir ; mkdir $Dir && cd $Dir || echo "$Dir was not created." [student@studentvm1 testdir]$
像 command1 && command2 這樣的控制語(yǔ)句能夠運(yùn)行的原因是,每條命令執(zhí)行完畢時(shí)都會(huì)給 shell 發(fā)送一個(gè)返回碼,用來(lái)表示它執(zhí)行成功與否。默認(rèn)情況下,返回碼為 0 表示成功,其他任何正值表示失敗。一些系統(tǒng)管理員使用的工具用值為 1 的返回碼來(lái)表示失敗,但其他很多程序使用別的數(shù)字來(lái)表示失敗。
Bash 的內(nèi)置變量 $? 可以顯示上一條命令的返回碼,可以在腳本或者命令行中非常方便地檢查它。要查看返回碼,讓我們從運(yùn)行一條簡(jiǎn)單的命令開(kāi)始,返回碼的結(jié)果總是上一條命令給出的。
[student@studentvm1 testdir]$ ll ; echo "RC = $?" total 1264 drwxrwxr-x 2 student student 4096 Mar 2 08:21 chapter25 drwxrwxr-x 2 student student 4096 Mar 21 15:27 chapter26 -rwxr-xr-x 1 student student 92 Mar 20 15:53 TestFile1 drwxrwxr-x. 2 student student 663552 Feb 21 14:12 testdir drwxr-xr-x. 2 student student 4096 Dec 22 13:15 Videos RC = 0 [student@studentvm1 testdir]$
在這個(gè)例子中,返回碼為零,意味著命令執(zhí)行成功了?,F(xiàn)在對(duì) root 的家目錄測(cè)試一下,你應(yīng)該沒(méi)有權(quán)限:
[student@studentvm1 testdir]$ ll /root ; echo "RC = $?" ls: cannot open directory '/root': Permission denied RC = 2 [student@studentvm1 testdir]$
返回碼是 2,表明非 root 用戶沒(méi)有權(quán)限進(jìn)入這個(gè)目錄。你可以利用這些返回碼,用控制運(yùn)算符來(lái)改變程序執(zhí)行的順序。
將 Bash 看作一門(mén)編程語(yǔ)言,并從這個(gè)視角介紹了它的簡(jiǎn)單語(yǔ)法和基礎(chǔ)工具。我們學(xué)習(xí)了如何將數(shù)據(jù)輸出到 STDOUT,怎樣使用變量和控制運(yùn)算符。
上述內(nèi)容就是Bash的語(yǔ)法和工具都有哪些,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。