標籤:目錄 情況 變數定義 不同 width use 第一條 許可權 3.2
BASH 的基本文法
- 最簡單的例子 —— Hello World!
- 關於輸入、輸出和錯誤輸出
- BASH 中對變數的規定(與 C 語言的異同)
- BASH 中的基本流程式控制制文法
- 函數的使用
2.1 最簡單的例子 —— Hello World!
幾乎所有的講解編程的書給讀者的第一個例子都是 Hello World 程式,那麼我們今天也就從這個例子出發,來逐步瞭解 BASH。
用 vi 編輯器編輯一個 hello 檔案如下:
#!/bin/bash
# This is a very simple example
echo Hello World
這樣最簡單的一個 BASH 程式就編寫完了。這裡有幾個問題需要說明一下:
一,第一行的 #! 是什麼意思
二,第一行的 /bin/bash 又是什麼意思
三,第二行是注釋嗎
四,echo 語句
五,如何執行該程式
#! 是說明 hello 這個檔案的類型的,有點類似於 Windows 系統下用不同檔案尾碼來表示不同檔案類型的意思(但不相同)。Linux 系統根據 “#!” 及該字串後面的資訊確定該檔案的類型,關於這一問題同學們回去以後可以通過 “man magic”命令 及 /usr/share/magic 檔案來瞭解這方面的更多內容。在 BASH 中 第一行的 “#!” 及後面的 “/bin/bash” 就表明該檔案是一個 BASH 程式,需要由 /bin 目錄下的 bash 程式來解釋執行。BASH 這個程式一般是存放在 /bin 目錄下,如果你的 Linux 系統比較特別,bash 也有可能被存放在 /sbin 、/usr/local/bin 、/usr/bin 、/usr/sbin 或 /usr/local/sbin 這樣的目錄下;如果還找不到,你可以用 “locate bash” “find / -name bash 2> /dev/null” 或 “whereis bash” 這三個命令找出 bash 所在的位置;如果仍然找不到,那你可能需要自己動手安裝一個 BASH 軟體包了。
第二行的 “# This is a …” 就是 BASH 程式的注釋,在 BASH 程式中從“#”號(注意:後面緊接著是“!”號的除外)開始到行尾的多有部分均被看作是程式的注釋。的三行的 echo 語句的功能是把 echo 後面的字串輸出到標準輸出中去。由於 echo 後跟的是 “Hello World” 這個字串,因此 “Hello World”這個字串就被顯示在控制台終端的螢幕上了。需要注意的是 BASH 中的絕大多數語句結尾處都沒有分號。
如何執行該程式呢?有兩種方法:一種是顯式制定 BASH 去執行:
$ bash hello 或
$ sh hello (這裡 sh 是指向 bash 的一個連結,“lrwxrwxrwx 1 root root 4 Aug 20 05:41 /bin/sh -> bash”)
或者可以先將 hello 檔案改為可以執行的檔案,然後直接運行它,此時由於 hello 檔案第一行的 “#! /bin/bash” 的作用,系統會自動用/bin/bash 程式去解釋執行 hello 檔案的:
$ chmod u+x hello
$ ./hello
此處沒有直接 “$ hello”是因為目前的目錄不是目前使用者可執行檔的預設目錄,而將目前的目錄“.”設為預設目錄是一個不安全的設定。
需要注意的是,BASH 程式被執行後,實際上 Linux 系統是另外開設了一個進程來啟動並執行。
2.2 關於輸入、輸出和錯誤輸出
在字元終端環境中,標準輸入/標準輸出的概念很好理解。輸入即指對一個應用程式 或命令的輸入,無論是從鍵盤輸入還是從別的檔案輸入;輸出即指應用程式或命令產生的一些資訊;與 Windows 系統下不同的是,Linux 系統下還有一個標準錯誤輸出的概念,這個概念主要是為程式調試和系統維護目的而設定的,錯誤輸出於標準輸出分開可以讓一些進階的錯誤資訊不干擾正常的輸出 資訊,從而方便一般使用者的使用。
在 Linux 系統中:標準輸入(stdin)預設為鍵盤輸入;標準輸出(stdout)預設為螢幕輸出;標準錯誤輸出(stderr)預設也是輸出到螢幕(上面的 std 表示 standard)。在 BASH 中使用這些概念時一般將標準輸出表示為 1,將標準錯誤輸出表示為 2。下面我們舉例來說明如何使用他們,特別是標準輸出和標準錯誤輸出。
輸入、輸出及標準錯誤輸出主要用於 I/O 的重新導向,就是說需要改變他們的預設設定。先看這個例子:
$ ls > ls_result
$ ls -l >> ls_result
上面這兩個命令分別將 ls 命令的結果輸出重新導向到 ls_result 檔案中和追加到 ls_result 檔案中,而不是輸出到螢幕上。”>”就是輸出(標準輸出和標準錯誤輸出)重新導向的代表符號,連續兩個 “>” 符號,即 “>>” 則表示不清除原來的而追加輸出。下面再來看一個稍微複雜的例子:
$ find /home -name lost* 2> err_result
這個命令在 “>” 符號之前多了一個 “2″,”2>” 表示將標準錯誤輸出重新導向。由於 /home 目錄下有些目錄由於許可權限制不能訪問,因此會產生一些標準錯誤輸出被存放在 err_result 檔案中。大家可以設想一下 find /home -name lost* 2>>err_result 命令會產生什麼結果?
如果直接執行 find /home -name lost* > all_result ,其結果是只有標準輸出被存入 all_result 檔案中,要想讓標準錯誤輸出和標準輸入一樣都被存入到檔案中,那該怎麼辦呢?看下面這個例子:
$ find /home -name lost* > all_result 2>& 1
上面這個例子中將首先將標準錯誤輸出也重新導向到標準輸出中,再將標準輸出重新導向到 all_result 這個檔案中。這樣我們就可以將所有的輸出都儲存到檔案中了。為實現上述功能,還有一種簡便的寫法如下:
$ find /home -name lost* >& all_result
如果那些出錯資訊並不重要,下面這個命令可以讓你避開眾多無用出錯資訊的幹擾:
$ find /home -name lost* 2> /dev/null
同學們回去後還可以再實驗一下如下幾種重新導向方式,看看會出什麼結果,為什嗎?
$ find /home -name lost* > all_result 1>& 2
$ find /home -name lost* 2> all_result 1>& 2
$ find /home -name lost* 2>& 1 > all_result
另外一個非常有用的重新導向操作符是 “-”,請看下面這個例子:
$ (cd /source/directory && tar cf – . ) | (cd /dest/directory && tar xvfp -)
該命令表示把 /source/directory 目錄下的所有檔案通過壓縮和解壓,快速的全部移動到 /dest/directory 目錄下去,這個命令在 /source/directory 和 /dest/directory 不處在同一個檔案系統下時將顯示出特別的優勢。
下面還幾種不常見的用法:
n<&- 表示將 n 號輸入關閉
<&- 表示關閉標準輸入(鍵盤)
n>&- 表示將 n 號輸出關閉
>&- 表示將標準輸出關閉
2.3 BASH 中對變數的規定(與 C 語言的異同)
好了下面我們進入正題,先看看 BASH 中的變數是如何定義和使用的。對於熟悉 C 語言的程式員,我們將解釋 BASH 中的定義和用法與 C 語言中有何不同。
2.3.1. BASH 中的變數介紹
我們先來從整體上把握一下 BASH 中變數的用法,然後再去分析 BASH 中變數使用與 C 語言中的不同。BASH 中的變數都是不能含有保留字,不能含有 “-” 等保留字元,也不能含有空格。
2.3.1.1 簡單變數
在 BASH 中變數定義是不需要的,沒有 “int i” 這樣的定義過程。如果想用一個變數,只要他沒有在前面被定義過,就直接可以用,當然你使用該變數的第一條語句應該是對他賦初值了,如果你不賦初值也沒關 系,只不過該變數是空( 注意:是 NULL,不是 0 )。不給變數賦初值雖然文法上不反對,但不是一個好的編程習慣。好了我們看看下面的例子:
首先用 vi 編輯下面這個檔案 hello2:
#!/bin/bash
# give the initialize value to STR
STR=”Hello World”
echo $STR
在上面這個程式中我們需要注意下面幾點:
一,變數賦值時,‘=’左右兩邊都不能有空格;
二,BASH 中的語句結尾不需要分號(”;”);
三,除了在變數賦值和在FOR迴圈語句頭中,BASH 中的變數使用必須在變數前加”$”符號,同學們可以將上面程式中第三行改為 “echo STR” 再試試,看看會出什麼結果。==>output: STR
四,由於 BASH 程式是在一個新的進程中啟動並執行,所以該程式中的變數定義和賦值不會改變其他進程或原始 Shell 中同名變數的值,也不會影響他們的運行。
更細緻的文檔甚至提到以但引號括起來的變數將不被 BASH 解釋為變數,如 ‘$STR’ ,而被看成為純粹的字串。而且更為標準的變數引用方式是 ${STR} 這樣的,$STR 自不過是對 ${STR} 的一種簡化。在複雜情況下(即有可能產生歧義的地方)最好用帶 {} 的表示方式。
BASH 中的變數既然不需要定義,也就沒有類型一說,一個變數即可以被定義為一個字串,也可以被再定義為整數。如果對該變數進行整數運算,他就被解釋為整數;如果對他進行字串操作,他就被看作為一個字串。請看下面的例子:
#!/bin/bash
x=1999
let “x = $x + 1″
echo $x
x=”olympic’”$x
echo $x
關於整數變數計算,有如下幾種:” + – * / % “,他們的意思和字面意思相同。整數運算一般通過 let 和 expr 這兩個指令來實現,如對變數 x 加 1 可以寫作:let “x = $x + 1“ 或者 x=`expr $x + 1`
在比較操作上,整數變數和字串變數各不相同,詳見下表:
對應的操作 |
整數操作 |
字串操作 |
相同 |
-eq |
= |
不同 |
-ne |
!= |
大於 |
-gt |
> |
小於 |
-lt |
< |
大於或等於 |
-ge |
|
小於或等於 |
-le |
|
為空白 |
|
-z |
不為空白 |
|
-n |
比如:
比較字串 a 和 b 是否相等就寫作:if [ $a = $b ]
判斷字串 a 是否為空白就寫作: if [ -z $a ]
判斷整數變數 a 是否大於 b 就寫作:if [ $a -gt $b ]
更細緻的文檔推薦在字串比較時盡量不要使用 -n ,而用 ! -z 來代替。(其中符號 “!” 表示求反操作)
BASH 中的變數除了用於對 整數 和 字串 進行操作以外,另一個作用是作為檔案變數。BASH 是 Linux 作業系統的 Shell,因此系統的檔案必然是 BASH 需要操作的重要對象,如 if [ -x /root ] 可以用於判斷 /root 目錄是否可以被目前使用者進入。下表列出了 BASH 中用於判斷檔案屬性的操作符:
運算子 |
含義( 滿足下面要求時返回 TRUE ) |
-e file |
檔案 file 已經存在 |
-f file |
檔案 file 是普通檔案 |
-s file |
檔案 file 大小不為零 |
-d file |
檔案 file 是一個目錄 |
-r file |
檔案 file 對目前使用者可以讀取 |
-w file |
檔案 file 對目前使用者可以寫入 |
-x file |
檔案 file 對目前使用者可以執行 |
-g file |
檔案 file 的 GID 標誌被設定 |
-u file |
檔案 file 的 UID 標誌被設定 |
-O file |
檔案 file 是屬於目前使用者的 |
-G file |
檔案 file 的組 ID 和目前使用者相同 |
file1 -nt file2 |
檔案 file1 比 file2 更新 |
file1 -ot file2 |
檔案 file1 比 file2 更老 |
注意:上表中的 file 及 file1、file2 都是指某個檔案或目錄的路徑。
2.3.1.1. 關於局部變數
在 BASH 程式中如果一個變數被使用了,那麼直到該程式的結尾,該變數都一直有效。為了使得某個變數存在於一個局部程式塊中,就引入了局部變數的概念。BASH 中,在變數首次被賦初值時加上 local 關鍵字就可以聲明一個局部變數,如下面這個例子:
#!/bin/bash
HELLO=Hello
function hello {
local HELLO=World
echo $HELLO
}
echo $HELLO
hello
echo $HELLO
該程式的執行結果是:
Hello
World
Hello
這個執行結果表明全域變數 $HELLO 的值在執行函數 hello 時並沒有被改變。也就是說局部變數 $HELLO 的影響只存在於函數那個程式塊中。
2.3.2. BASH 中的變數與 C 語言中變數的區別
這裡我們為原來不熟悉 BASH 編程,但是非常熟悉 C 語言的程式員總結一下在 BASH 環境中使用變數需要注意的問題。
1,BASH 中的變數在引用時都需要在變數前加上 “$” 符號( 第一次賦值及在For迴圈的頭部不用加 “$”符號 );
2,BASH 中沒有浮點運算,因此也就沒有浮點類型的變數可用;
3,BASH 中的整形變數的比較符號與 C 語言中完全不同,而且整形變數的算術運算也需要經過 let 或 expr 語句來處理;
2.4 BASH 中的基本流程式控制制文法
BASH 中幾乎含有 C 語言中常用的所有控制結構,如條件分支、迴圈等,下面逐一介紹。
2.4.1 if…then…else
if 語句用於判斷和分支,其文法規則和 C 語言的 if 非常相似。其幾種基本結構為:
if [ expression ]
then
statments
fi
或者
if [ expression ]
then
statments
else
statments
fi
或者
if [ expression ]
then
statments
else if [ expression ]
then
statments
else
statments
fi
或者
if [ expression ]
then
statments
elif [ expression ]
then
statments
else
statments
fi
值得說明的是如果你將 if 和 then 簡潔的寫在一行裡面,就必須在 then 前面加上分號,如:if [ expression ]; then … 。下面這個例子說明了如何使用 if 條件判斷語句:
#!/bin/bash
if [ $1 -gt 90 ]
then
echo “Good, $1″
elif [ $1 -gt 70 ]
then
echo “OK, $1″
else
echo “Bad, $1″
fi
exit 0
上面例子中的 $1 是指命令列的第一個參數,這個會在後面的“BASH 中的特殊保留字”中講解。
2.4.2 for
for 迴圈結構與 C 語言中有所不同,在 BASH 中 for 迴圈的基本結構是:
for $var in
do
statments
done
其中 $var 是迴圈控制變數,
Linux Bash Shell編程快速入門