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" 再試試,看看會出什么結果。
四,由于 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 [list]
do
statments
done其中 $var 是循環控制變量,[list] 是 $var 需要遍歷的一個集合,do/done 對包含了循環體,相當于 C 語言中的一對大括號。另外如果do
和 for 被寫在同一行,必須在 do 前面加上 ";"。如: for $var in
[list]; do 。下面是一個運用 for 進行循環的例子:#!/bin/bash
for day in Sun Mon Tue Wed Thu Fri Sat
do
echo $day
done
# 如果列表被包含在一對雙引號中,則被認為是一個元素
for day in "Sun Mon Tue Wed Thu Fri Sat"
do
echo $day
done
exit 0注意上面的例子中,在 for 所在那行的變量 day 是沒有加 "$" 符號的,而在循環體內,echo 所在行變量 $day 是必須加上
"$" 符號的。另外如果寫成 for day 而沒有后面的 in [list] 部分,則 day 將取遍命令行的所有參數。如 這個程序 :#!/bin/bash
for param
do
echo $param
done
exit 0上面這個程序將列出所有命令行參數。for 循環結構的循環體被包含在 do/done 對中,這也是后面的 while、until 循環所具有的特點。
2.4.3 while
while 循環的基本結構是:
while [ condition ]
do
statments
done這個結構請大家自己編寫一個例子來驗證。
2.4.4 until
until 循環的基本結構是:
until [ condition is TRUE ]
do
statments
done這個結構也請大家自己編寫一個例子來驗證。
2.4.5 case
BASH 中的 case 結構與 C 語言中的 switch 語句的功能比較類似,可以用于進行多項分支控制。其基本結構是:
case "$var" in
condition1 )
statments1;;
condition2 )
statments2;;
...
* )
default statments;;
esac下面這個程序是運用 case 結構進行分支執行的 例子 :
#!/bin/bash
echo "Hit a key, then hit return."
read Keypress
case "$Keypress" in
[a-z] ) echo "Lowercase letter";;
[A-Z] ) echo "Uppercase letter";;
[0-9] ) echo "Digit";;
* ) echo "Punctuation, whitespace, or other";;
esac
exit 0上面例子中的第四行 "read Keypress" 一句中的 read 語句表示從鍵盤上讀取輸入。這個命令將在本講義的 BASH
的其他高級問題 中講解。2.4.6 break/continue
熟悉 C 語言編程的都很熟悉 break 語句和 continue 語句。BASH 中同樣有這兩條語句,而且作用和用法也和 C 語言中相同,break
語句可以讓程序流程從當前循環體中完全跳出,而 continue 語句可以跳過當次循環的剩余部分并直接進入下一次循環。?
2.5????函數的使用
BASH 是一個相對簡單的腳本語言,不過為了方便結構化的設計,BASH 中也提供了函數定義的功能。BASH 中的函數定義很簡單,只要向下面這樣寫就可以了:
function my_funcname {
code block
}或者
my_funcname() {
code block
}上面的第二種寫法更接近于 C 語言中的寫法。BASH 中要求函數的定義必須在函數使用之前,這是和 C 語言用頭文件說明函數方法的不同。
更進一步的問題是如何給函數傳遞參數和獲得返回值。BASH 中函數參數的定義并不需要在函數定義處就制定,而只需要在函數被調用時用 BASH 的保留變量
$1 $2 ... 來引用就可以了;BASH 的返回值可以用 return 語句來指定返回一個特定的整數,如果沒有 return 語句顯式的返回一個返回值,則返回值就是該函數最后一條語句執行的結果(一般為
0,如果執行失敗返回錯誤碼)。函數的返回值在調用該函數的程序體中通過 $? 保留字來獲得。下面我們就來看一個用函數來計算整數平方的 例子 :#!/bin/bash
square() {
let "res = $1 * $1"
return $res
}
square $1
result=$?
echo $result
exit 0?
?
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
