bash shell文件的開頭:
#!/bin/bash
一個簡單的bash例子,在屏幕中輸出Hello World
#!/bin/bash
echo "Hello world!"
一段簡單的Shell
首先來一段簡單的Shell腳本,整體上對Shell有一個簡單的認識。
上面是一段簡單的Shell程序,實現在功能爲:
- 在用戶主目錄下創建一個shell_test文件夾;
- 在用戶主目錄下創建10個規定命名格式的空文件。
由於是第一個Shell程序,所以有必要逐行解釋一下,留下一個好的印象。
- 第一行:指定腳本解釋器,這裏是用/bin/bash做解釋器;
- 第二行:切換到當前用戶的home目錄;
- 第三行:創建一個名爲shell_test的空目錄;
- 第四、五行:for循環,一共循環10次;
- 第六行:創建10個名稱爲test0.txt, test1.txt格式的空文件。
cd、mkdir和touch都是系統自帶的程序,一般在/bin目錄下;而for、do和done都是Shell的關鍵字。
Shell中使用#開頭的行就是註釋。
一個簡單的程序之後,我們就開始進入Shell的語法學習吧。
變量
從變量開始學習這段旅程。
基礎知識
1. 在Shell中,使用變量之前不需要事先聲明,只是通過使用它們來創建它們;
2. 在默認情況下,所有變量都被看做是字符串,並以字符串來存儲;
3. Shell變量是區分大小寫的;
4. 在Shell中,通過在變量名前加一個$符號來訪問它的內容,無論何時想要獲取變量內容,都必須在它前面加一個$符號;
下面通過一段Shell腳本來詳細的說明上面的內容:
使用read
在Shell中,我們可以使用read命令將用戶的輸入賦值給一個變量。這個命令需要一個參數,即準備讀入用戶輸入數據的變量名,然後它會等待用戶輸入數據。通常情況下,在用戶按下回車鍵時,read命令結束。例如以下代碼:
引號的使用技巧
在上面的代碼中也說了,如果字符串中包含了空格,就需要使用引號將字符串括起來,而這只是引號的一個簡單的使用。 像$var1這種的變量在引號中的行爲取決於你所使用的引號類型。這句話有以下兩層意思:
- 如果把一個$變量表達式放在雙引號中,程序執行到這一行時就會把變量替換爲它的值;
- 如果把一個$變量表達式放在單引號中,就不會發生替換現象;
但是,我們可以通過在$字符前面加上一個\字符取消它的特殊含義,也就是經常說的轉義字符。下面通過一段簡單的代碼來理解上面內容的意思:
環境變量
當一個Shell腳本程序開始執行時,一些變量根據環境設置中的值進行初始化,一般比較常用的有以下幾個:
- $HOME:當前用戶的主目錄,例如:/home/jelly;
- $PATH:以冒號分隔的用來搜索命令的目錄列表;
- $0:Shell腳本的名字;
- $#:傳遞給腳本的參數個數;
- $$:Shell腳本的進程號,腳本程序通常會用它來生成一個唯一的臨時文件。
參數變量
如果腳本程序在調用時帶有參數,一些額外的變量就會被創建。即使沒有傳遞任何參數,環境變量$#也依然存在,只不過它的值是0罷了。例如以下實力代碼:
輸出如下:
BASH 中有一些保留變量,下面列出了一些:
$IFS 這個變量中保存了用於分割輸入參數的分割字符,默認識空格。
$HOME 這個變量中存儲了當前用戶的根目錄路徑。
$PATH 這個變量中存儲了當前 Shell 的默認路徑字符串。
$PS1 表示第一個系統提示符。
$PS2 表示的二個系統提示符。
$PWD 表示當前工作路徑。
$EDITOR 表示系統的默認編輯器名稱。
$BASH 表示當前 Shell 的路徑字符串。
$0, $1, $2, ...
表示系統傳給腳本程序或腳本程序傳給函數的第0個、第一個、第二個等參數。
$# 表示腳本程序的命令參數個數或函數的參數個數。
$$ 表示該腳本程序的進程號,常用於生成文件名唯一的臨時文件。
$? 表示腳本程序或函數的返回狀態值,正常爲 0,否則爲非零的錯誤號。
$* 表示所有的腳本參數或函數參數。
$@ 和 $* 涵義相似,但是比 $* 更安全。
$! 表示最近一個在後臺運行的進程的進程號。
條件判斷
我們知道,所有程序設計語言的基礎是對條件進行測試判斷,並根據測試結果採取不同行動的能力。在總結之前,先看看Shell腳本程序裏可以使用的條件結構,然後再來看看使用這些條件的控制結構。
一個Shell腳本能夠對任何可以從命令行上調用的命令的退出碼進行判斷,這其中也包括我們寫的Shell腳本程序。這就是爲什麼要在所有自己編寫的腳本程序的結尾包括一條返回值的exit命令的重要原因。
test或[命令
在實際工作中,大多數腳本程序都會廣泛使用Shell的布爾判斷命令[或test。在一些系統上,這兩個命令其實是一樣的,只是爲了增強可讀性,當使用[命令時,我們還使用符號]來結尾。寫了這麼多程序了,還是頭一次見,將一個[作爲一個命令。算我孤陋寡聞了。下面就通過一個簡單的例子來看看test和[是如何使用的。
我們通過使用-f來判斷指定文件是否存在。test命令可以使用的條件類型可以歸爲3類:
- 字符串比較;
- 算術比較;
- 文件相關的條件測試。
下面就分別看看。
字符串比較 | 結果 |
---|---|
string1 = string2 | 如果兩個字符串相同,結果就爲真 |
string1 != string2 | 如果兩個字符串不同,結果就爲真 |
-n string | 如果字符串不爲空,則結果爲真 |
-z string | 如果字符串爲一個空串(null),則結果爲真 |
算術比較 | 結果 |
---|---|
expression1 -eq expression2 | 如果兩個表達式相等,則結果爲真 |
expression1 -ne expression2 | 如果兩個表達式不等,則結果爲真 |
expression1 -gt expression2 | 如果expression1大於expression2,則爲真 |
expression1 -ge expression2 | 如果expression1大於等於expression2,則爲真 |
expression1 -lt expression2 | 如果expression1小於expression2,則爲真 |
expression1 -le expression2 | 如果expression1小於等於expression2,則爲真 |
!expression | 表達式爲假,則結果就爲真;反之亦然 |
文件條件測試 | 結果 |
---|---|
-d file | 如果文件是一個目錄,則爲真 |
-f file | 如果文件是一個普通文件,則爲真;也可以用來測試文件是否存在 |
-r file | 如果文件可讀,則結果爲真 |
-s file | 如果文件大小不爲0,則結果爲真 |
-w file | 如果文件可寫,則結果爲真 |
-x file | 如果文件可執行,則結果爲真 |
控制結構
Shell也有一組控制結構,它們與其它程序語言中的控制接口很相似,下面就分開來總結它們。
if語句
結構如下:
代碼示例:
elif語句
結構如下
一個很容易出錯的問題。例如以下代碼:
上面這段代碼很簡單,運行以下,如果你不輸入yes或no,就會運行出錯,得到以下提示信息:
這是爲何?代碼中有if [ $timeofday = "yes" ],當我不輸入任何內容時,這個if語句就會變成這樣if [ = "yes" ],很明顯,這不是一個合法的條件。爲了避免出現這種情況,我們必須給變量加上引號,改成這樣if [ "$timeofday" = "yes" ]。這樣就沒有問題了。
for語句
結構如下:
代碼示例:
在文章的開頭,那段簡單的代碼中,也包含了for的簡單使用。
while語句
結構如下:
代碼示例:
until語句
結構如下:
它與while循環很相似,只是把條件測試反過來了;也就是說,循環將反覆執行直到條件爲真。
case語句
結構如下:
case的代碼結構相對來說是比較複雜的。case結構具備匹配多個模式,然後執行多條相關語句的能力,這使得它非常適合於處理用戶的輸入。下面通過一個實例來看看case的具體使用。
當case語句被執行時,它會把變量input的內容與各字符串依次進行比較。一旦某個字符串與輸入匹配成功,case命令就會執行緊隨右括號)後面的代碼,然後就結束。 在代碼中,最後面的*表示匹配任何字符串,我們在寫代碼時,總是在其它匹配之後再添加一個*以確保如果沒有字符串得到匹配,case語句也會執行某個默認動作。 由於case比較複雜,所以不得不再來一段代碼,究其用法,如下:
上面這段代碼,使用了|符號,也就是說,也就是合併了多個匹配模式;同時還使用了*通配符;沒有問題,上面的代碼運行的很好。
&&和||操作符
Shell中也支持&&和||符號,和C++語言中的是一樣;比如:
從左開始順序執行每條命令,如果一條命令返回的是true,它右邊的下一條命令才能執行。如果此持續直到有一條命令返回false,或者列表中的所有命令都執行完畢;遵循“短路”規則。
從左開始順序執行每條命令,如果一條命令返回的是false,它右邊的下一條命令才能夠被執行。如此持續直到有一條命令返回true,或者列表中的所有命令都執行完畢。
語句塊
在Shell中也有語句塊,使用{}來定義一個語句塊。我們可以把多條語句放到一個語句塊中執行。
函數
函數,這麼NB的東西,Shell怎麼能少呢。定義函數的結構如下:
代碼示例:
腳本程序從自己的頂部開始執行,當它遇到了foo() {結構時,它知道腳本正在定義一個名爲foo的函數。當執行到單獨的foo時,Shell就知道應該去執行剛纔定義的函數了。函數執行完畢以後,腳本接着foo後的代碼繼續執行。 當一個函數被調用時,腳本程序的位置參數($*、$@、$#、$1、$2等)會被替換爲函數的參數,這也是我們讀取傳遞給函數的參數的方法。當函數執行完畢後,這些參數會恢復爲它們先前的值。 我們可以使用local關鍵字在Shell函數中聲明局部變量,局部變量將僅在函數的作用範圍內有效。此外,函數可以訪問全局作用範圍內的其它Shell變量。如果一個局部變量和一個全局變量的名字相同,前者就會覆蓋後者,但僅限於函數的作用範圍之內,例如以下代碼:
輸出如下:
用 BASH 設計簡單用戶界面
BASH 中提供了一個小的語句格式,可以讓程序快速的設計出一個字符界面的用戶交互選擇的菜單,該功能就是由 select 語句來實現的,select 語句的語法爲:
select var in
do
statments use $var
done
上面的語法結構在執行後,BASH 會將 中的所有項加上數字列在屏幕上等待用戶選擇,在用戶作出選擇後,變量 $var 中就包含了那個被選中的字符串,然後就可以對該變量進行需要的操作了。我們可以從下面的例子中更直觀的來理解這個功能:
#!/bin/bash
OPTIONS="Hello Quit"
select opt in $OPTIONS; do
if [ "$opt" = "Quit" ]; then
echo done
exit
elif [ "$opt" = "Hello" ]; then
echo Hello World
else
clear
echo bad option
fi
done
exit 0<span style="font-family:Tahoma, Helvetica, Hei, SimSun, sans-serif;"><span style="font-size: 14px; line-height: 25.2px;">
</span></span>