<!-- /* Font Definitions */ @font-face {font-family:"MS 明朝"; panose-1:2 2 6 9 4 2 5 8 3 4; mso-font-alt:"MS Mincho"; mso-font-charset:128; mso-generic-font-family:roman; mso-font-pitch:fixed; mso-font-signature:-1610612033 1757936891 16 0 131231 0;} @font-face {font-family:SimSun; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:宋體; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:Century; panose-1:2 4 6 4 5 5 5 2 3 4; mso-font-charset:0; mso-generic-font-family:roman; mso-font-pitch:variable; mso-font-signature:647 0 0 0 159 0;} @font-face {font-family:"MS Pゴシック"; panose-1:2 11 6 0 7 2 5 8 2 4; mso-font-charset:128; mso-generic-font-family:modern; mso-font-pitch:variable; mso-font-signature:-1610612033 1757936891 16 0 131231 0;} @font-face {font-family:"/@SimSun"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"/@MS 明朝"; panose-1:2 2 6 9 4 2 5 8 3 4; mso-font-charset:128; mso-generic-font-family:roman; mso-font-pitch:fixed; mso-font-signature:-1610612033 1757936891 16 0 131231 0;} @font-face {font-family:"/@MS Pゴシック"; panose-1:2 11 6 0 7 2 5 8 2 4; mso-font-charset:128; mso-generic-font-family:modern; mso-font-pitch:variable; mso-font-signature:-1610612033 1757936891 16 0 131231 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0mm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:Century; mso-fareast-font-family:"MS 明朝"; mso-bidi-font-family:"Times New Roman"; mso-font-kerning:1.0pt;} a:link, span.MsoHyperlink {color:blue; text-decoration:underline; text-underline:single;} a:visited, span.MsoHyperlinkFollowed {color:purple; text-decoration:underline; text-underline:single;} p {mso-margin-top-alt:auto; margin-right:0mm; mso-margin-bottom-alt:auto; margin-left:0mm; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"MS Pゴシック"; mso-bidi-font-family:"MS Pゴシック";} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:595.3pt 841.9pt; margin:99.25pt 30.0mm 30.0mm 30.0mm; mso-header-margin:42.55pt; mso-footer-margin:49.6pt; mso-paper-source:0; layout-grid:18.0pt;} div.Section1 {page:Section1;} -->
Linux 的 shell 編 程
http://tech.sina.com.cn/c/1338.html
Shell 本身是一個用 C 語 言 編 寫的程序,它是用 戶 使用 Linux 的 橋 樑。 Shell 既是一 種 命令 語 言,又是一 種 程序 設計語 言。作 爲 命令 語 言,它交互式地解 釋 和 執 行用 戶輸 入的命令;作 爲 程序 設計語 言,它定 義 了各 種變 量和參 數,並提供了 許 多在高 級語 言中才具有的控制 結 構,包括循 環 和分支。它 雖 然不是 Linux 系 統 核心的一部分,但它 調 用了系 統 核心的大部分功能來 執 行程序、建 立文件並以並行的方式 協調 各個程序的運行。因此, 對 於用 戶 來 說 , shell 是最重要的 實 用程序,深入瞭解和熟 練 掌握 shell 的特性極其使用方法,是用好 Linux 系 統 的 關鍵 。可以 說 , shell 使用的熟 練 程度反映了用 戶對 Linux 使用的熟 練 程度。
一、什 麼 是 shell
當一個用 戶 登 錄 Linux 系 統 之後,系 統 初始化程序 init 就 爲每 一個用 戶 運行一個稱 爲 shell( 外殼 ) 的程序。那 麼 , shell 是什 麼 呢? 確切一點 說 , shell 就是一個命令行解 釋 器,它 爲 用 戶 提供了一個向 Linux 內核 發 送 請 求以便運行程序的界面系 統級 程序,用 戶 可以用 shell 來啓 動 、 掛起、停止甚至是 編 寫一些程序。
當用 戶 使用 Linux 時 是通 過 命令來完成所需工作的。一個命令就是用 戶 和 shell 之 間對話 的一個基本 單 位,它是由多個字符 組 成並以 換 行 結 束的 字符串。 shell 解 釋 用 戶輸 入的命令,就象 DOS 裏的 command.com 所做的一 樣 ,所不同的是,在 DOS 中, command.com 只有一個,而 在 Linux 下比 較 流行的 shell 有好幾個, 每 個 shell 都各有千秋。一般的 Linux 系 統 都將 bash 作 爲 默 認 的 shell 。
二、幾 種 流行的 shell
目前流行的 shell 有 ash 、 bash 、 ksh 、 csh 、 zsh 等,你可以用下面的命令來 查 看你自己的 shell 類 型:
#echo $SHELL
$SHELL 是一個 環 境 變 量,它 記錄 用 戶 所使用的 shell 類 型。你可以用命令:
#shell-name
來 轉換 到 別 的 shell , 這 裏 shell-name 是你想要 嘗試 使用的 shell 的名稱,如 ash 等。 這 個命令 爲 用 戶 又啓 動 了一個 shell , 這 個 shell 在最初登 錄 的那個 shell 之後,稱 爲 下 級 的 shell 或子 shell 。使用命令:
$exit
可以退出 這 個子 shell 。
使用不同的 shell 的原因在於它 們 各自都有自己的特點,下面作一個 簡單 的介 紹 :
1.ash
ash shell 是由 Kenneth Almquist 編 寫的, Linux 中佔用系 統資 源最少的一個小 shell ,它只包含 24 個內部命令,因而使用起來很不方便。
2.bash
bash 是 Linux 系 統 默 認 使用的 shell ,它由 Brian Fox 和 Chet Ramey 共同完成,是 Bourne Again Shell 的 縮 寫,內部命令一共有 40 個。 Linux 使用它作 爲 默 認 的 shell 是因 爲 它有 諸 如以下的特色:
(1) 可以使用 類 似 DOS 下面的 doskey 的功能,用方向 鍵查閱 和快速 輸 入並修改命令。
(2) 自 動 通 過查 找匹配的方式 給 出以某字符串 開頭 的命令。
(3) 包含了自身的幫助功能,你只要在提示符下面 鍵 入 help 就可以得到相 關 的幫助。
3.ksh
ksh 是 Korn shell 的 縮 寫,由 Eric Gisin 編 寫,共有 42 條內部命令。 該 shell 最大的 優 點是幾乎和商 業發 行版的 ksh 完全兼容, 這樣 就可以在不用花 錢購買 商 業 版本的情況下 嘗試 商 業 版本的性能了。
4.csh
csh 是Linux 比較 大的內核,它由以William Joy 爲 代表的共計 47 位作者編 成,共有52 個內部命令。該 shell 其實 是指向/bin/tcsh 這樣 的一個shell ,也就是說 ,csh 其實 就是tcsh 。
5.zch
zch 是Linux 最大的shell 之一,由Paul Falstad 完成,共有84 個內部命令。如果只是一般的用途,是沒有必要安裝這樣 的shell 的。
3. shell 程序 設計 ( 基 礎 部分 )
其 實 作 爲 命令 語 言交互式地解 釋 和 執 行用 戶輸 入的命令只是 shell 功能的一個方面, shell 還 可以用來 進 行程序 設計 ,它提供了定 義變 量和參數 的手段以及豐富的程序控制 結 構。使用 shell 編 程 類 似於 DOS 中的批 處 理文件,稱 爲 shell script ,又叫 shell 程序或 shell 命令文件。
1.shell 基本 語 法
shell 的基本 語 法主要就是如何 輸 入命令運行程序以及如何在程序之 間 通 過 shell 的一些參數提供便利手段來 進 行通 訊 。
(1) 輸 入 輸 出重定向
在 Linux 中, 每 一個 進 程都有三個特殊的文件描述指 針 : 標 準 輸 入 (standard input ,文件描述指 針爲 0) 、 標 準 輸 出 (standard output ,文件描述指 針爲 1) 、 標 準 錯誤輸 出 (standard error ,文件描述指 針爲 2) 。 這 三個特殊的文件描述指 針 使 進 程在一般情況下接收 標 準 輸 入 終 端的 輸 入,同 時 由 標 準 終 端來 顯 示 輸 出, Linux 同 時 也向使 用者提供可以使用普通的文件或管道來取代 這 些 標 準 輸 入 輸 出 設備 。在 shell 中,使用者可以利用 “>” 和 “<” 來 進 行 輸 入 輸 出重定向。如:
command>file :將命令的 輸 出 結 果重定向到一個文件。
command>&file :將命令的 標 準 錯誤輸 出一起重定向到一個文件。
command>>file :將 標 準 輸 出的 結 果追加到文件中。
command>>&file :將 標 準 輸 出和 標 準 錯誤輸 出的 結 構都追加到文件中。
command
(2) 管道 pipe
pipe 同 樣 可以在 標 準 輸 入 輸 出和 標 準 錯誤輸 出 間 做代替工作, 這樣 一來,可以將某一個程序的 輸 出送到另一個程序的 輸 入,其 語 法如下:
command1| command2[| command3...]
也可以 連 同 標 準 錯誤輸 出一起送入管道:
command1| &command2[|& command3...]
(3) 前臺和後臺
在 shell 下面,一個新 產 生的 進 程可以通 過 用命令後面的符號 “ ; ” 和 “&” 來分 別 以前臺和後臺的方式來 執 行, 語 法如下:
command
產 生一個前臺的 進 程,下一個命令 須 等 該 命令運行 結 束後才能 輸 入。
command &
產 生一個後臺的 進 程,此 進 程在後臺運行的同 時 ,可以 輸 入其他的命令。
2 。 shell 程序的 變 量和參數
像高 級 程序 設計語 言一 樣 , shell 也提供 說 明和使用 變 量的功能。 對 shell 來 講 ,所有 變 量的取 值 都是一個字符串, shell 程序採用 $var 的形式來引用名 爲 var 的 變 量的 值 。
Shell 有以下幾 種 基本 類 型的 變 量:
(1)shell 定 義 的 環 境 變 量
shell 在 開 始 執 行 時 就已 經 定 義 了一些和系 統 的工作 環 境有 關 的 變 量, 這 些 變 量用 戶還 可以重新定 義 ,常用的 shell 環 境 變 量有:
HOME :用於保存註冊目 錄 的完全路徑名。
PATH :用於保存用冒號分隔的目 錄 路徑名, shell 將按 PATH 變 量中 給 出的 順 序搜索 這 些目 錄 ,找到的第一個與命令名稱一致的可 執 行文件將被 執 行。
TERM : 終 端的 類 型。
UID :當前用 戶 的 標識 符,取 值 是由數字構成的字符串。
PWD :當前工作目 錄 的 絕對 路徑名, 該變 量的取 值 隨 cd 命令的使用而 變 化。
PS1 :主提示符,在特 權 用 戶 下,缺省的主提示符是 “#” ,在普通用 戶 下,缺省的主提示符是 “$” 。
PS2 :在 shell 接收用 戶輸 入命令的 過 程中,如果用 戶 在 輸 入行的末尾 輸 入 “/” 然後回 車 ,或者當用 戶 按回 車鍵時 shell 判斷出用 戶輸 入的命令沒有 結 束 時 , 顯 示 這 個 輔 助提示符,提示用 戶繼續輸 入命令的其餘部分,缺省的 輔 助提示符是 “>” 。
(2) 用 戶 定 義 的 變 量
用 戶 可以按照下面的 語 法 規則 定 義 自己的 變 量:
變 量名 = 變 量 值
要注意的一點是,在定 義變 量 時 , 變 量名前不 應 加符號 “$” ,在引用 變 量的內容 時則應 在 變 量名前加 “$” ;在 給變 量 賦值時 ,等號兩 邊 一定不能留空格,若 變 量中本身就包含了空格, 則 整個字符串都要用雙引號括起來。
在 編 寫 shell 程序 時 , 爲 了使 變 量名和命令名相區 別 ,建 議 所有的 變 量名都用大寫字母來表示。
有 時 我 們 想要在 說 明一個 變 量並 對 它 設 定 爲 一個特定 值 後就不在改 變 它的 值 , 這 可以用下面的命令來保 證 一個 變 量的只 讀 性:
readly 變 量名
在任何 時 候,建立的 變 量都只是當前 shell 的局部 變 量,所以不能被 shell 運行的其他命令或 shell 程序所利用, export 命令可以將一局部 變 量提供 給 shell 執 行的其他命令使用,其格式 爲 :
export 變 量名
也可以在 給變 量 賦值 的同 時 使用 export 命令:
export 變 量名 = 變 量 值
使用 export 說 明的 變 量,在 shell 以後運行的所有命令或程序中都可以 訪問 到。
(3) 位置參數
位置參數是一 種 在 調 用 shell 程序的命令行中按照各自的位置決定的 變 量,是在程序名之後 輸 入的參數。位置參數之 間 用空格分隔, shell 取第 一個位置參數替 換 程序文件中的 $1 ,第二個替 換 $2 ,依次 類 推。 $0 是一個特殊的 變 量,它的內容是當前 這 個 shell 程序的文件名,所以, $0 不是一個位 置參數,在 顯 示當前所有的位置參數 時 是不包括 $0 的。
(4) 預 定 義變 量
預 定 義變 量和 環 境 變 量相 類 似,也是在 shell 一 開 始 時 就定 義 了的 變 量,所不同的是,用 戶 只能根據 shell 的定 義 來使用 這 些 變 量,而不能重定 義 它。所有 預 定 義變 量都是由 $ 符和另一個符號 組 成的,常用的 shell 預 定 義變 量有:
$# :位置參數的數量
$* :所有位置參數的內容
$? :命令 執 行後返回的狀 態
$$ :當前 進 程的 進 程號
$! :後臺運行的最後一個 進 程號
$0 :當前 執 行的 進 程名
其中, “$?” 用於 檢查 上一個命令 執 行是否正確 ( 在 Linux 中,命令退出狀 態爲 0 表示 該 命令正確 執 行,任何非 0 值 表示命令出 錯 ) 。
“$$” 變 量最常 見 的用途是用作 臨時 文件的名字以保 證臨時 文件不會重 復 。
(5) 參數置換 的變 量
shell 提供了參數置 換 能力以便用 戶 可以根據不同的條件來 給變 量 賦 不同的 值 。參數置 換 的 變 量有四 種 , 這 些 變 量通常與某一個位置參數相 聯 系,根據指定的位置參數是否已 經設 置 類 決定 變 量的取 值 ,它 們 的 語 法和功能分 別 如下。
a. 變 量 =${ 參數 -word} :如果 設 置了參數, 則 用參數的 值 置 換變 量的 值 ,否 則 用 word 置 換 。即 這種變 量的 值 等於某一個參數的 值 ,如果 該 參數沒有 設 置, 則變 量就等於 word 的 值 。
b. 變 量 =${ 參數 =word} :如果 設 置了參數, 則 用參數的 值 置 換變 量的 值 ,否 則 把 變 量 設 置成 word 然後再用 word 替 換 參數的 值 。注意,位置參數不能用於 這種 方式,因 爲 在 shell 程序中不能 爲 位置參數 賦值 。
c. 變 量 =${ 參數? word} :如果 設 置了參數, 則 用參數的 值 置 換變 量的 值 ,否 則 就 顯 示 word 並從 shell 中退出,如果省略了 word , 則顯 示 標 準信 息。 這種變 量要求一定等於某一個參數的 值 ,如果 該 參數沒有 設 置,就 顯 示一個信息,然後退出,因此 這種 方式常用於出 錯 指示。
d. 變 量 =${ 參數 +word} :如果 設 置了參數, 則 用 word 置 換變 量,否 則 不 進 行置 換 。
所有 這 四 種 形式中的 “ 參數 ” 既可以是位置參數,也可以是另一個 變 量,只是用位置參數的情況比 較 多。
接下來以 bash 爲 例向大家介 紹 shell 程序 設計 的高 級 部分: shell 編 程的流程控制、 調試 方法及 shell 程序的運行方法, 順 便也向大家介 紹 一下 bash 的內部命令。
四、 shell 程序 設計 的流程控制
和其他高 級 程序 設計語 言一 樣 , shell 提供了用來控制程序 執 行流程的命令,包括條件分支和循 環結 構,用 戶 可以用 這 些命令建立非常 複雜 的程序。
與 傳統 的 語 言不同的是, shell 用於指定條件 值 的不是布 爾 表達式而是命令和字符串。
1.test 測試 命令
test 命令用於 檢查 某個條件是否成立,它可以 進 行數 值 、字符和文件三個方面的 測試 ,其 測試 符和相 應 的功能分 別 如下:
(1) 數 值測試 :
-eq :等於 則爲 真
-ne :不等於 則爲 真
-gt :大於 則爲 真
-ge :大於等於 則爲 真
-lt :小於 則爲 真
-le :小於等於 則爲 真
(2) 字符串 測試 :
= :等於 則爲 真
!= :不相等 則爲 真
-z 字符串:字符串 長 度 僞則爲 真
-n 字符串:字符串 長 度不 僞則爲 真
(3) 文件 測試 :
-e 文件名:如果文件存在 則爲 真
-r 文件名:如果文件存在且可 讀則爲 真
-w 文件名:如果文件存在且可寫 則爲 真
-x 文件名:如果文件存在且可 執 行 則爲 真
-s 文件名:如果文件存在且至少有一個字符 則爲 真
-d 文件名:如果文件存在且 爲 目 錄則爲 真
-f 文件名:如果文件存在且 爲 普通文件 則爲 真
-c 文件名:如果文件存在且 爲 字符型特殊文件 則爲 真
-b 文件名:如果文件存在且 爲塊 特殊文件 則爲 真
另外, Linux 還 提供了與 (“ ! ”) 、或 (“-o) 、非 (“-a”) 三個 邏輯 操作符用於將 測試 條件 連 接起來,其 優 先 級爲 : “ ! ” 最高, “-a” 次之, “-o” 最低。
同 時 , bash 也能完成 簡單 的算 術 運算,格式如下:
$[expression]
例如:var1=2
var2=$[var1*10+1]
則 : var2 的 值爲 21 。
2.if 條件 語 句
shell 程序中的條件分支是通 過 if 條件 語 句來 實現 的,其一般格式 爲 :
if 條件命令串
then
條件 爲 真 時 的命令串
else
條件 爲 假 時 的命令串
fi
3.for 循 環
for 循 環對 一個 變 量的可能的 值 都 執 行一個命令序列。 賦給變 量的幾個數 值 既可以在程序內以數 值 列表的形式提供,也可以在程序以外以位置參數的形式提供。 for 循 環 的一般格式 爲 :
for 變 量名
[in 數 值 列表 ]
do
若干個命令行
done
變 量名可以是用 戶選擇 的任何字符串,如果 變 量名是 var , 則 在 in 之後 給 出的數 值 將 順 序替 換 循 環 命令列表中的 $var 。如果省略了 in , 則變 量 var 的取 值 將是位置參數。 對變 量的 每 一個可能的 賦值 都將 執 行 do 和 done 之 間 的命令列表。
4.while 和 until 循 環
while 和 until 命令都是用命令的返回狀 態值 來控制循 環 的。 While 循 環 的一般格式 爲 :
while
若干個命令行 1
do
若干個命令行 2
done
只要 while 的 “ 若干個命令行 1” 中最後一個命令的返回狀 態爲 真, while 循 環 就 繼續執 行 do...done 之 間 的 “ 若干個命令行 2” 。
until 命令是另一 種 循 環結 構,它和 while 命令相似,其格式如下:
until
若干個命令行 1
do
若干個命令行 2
done
until 循 環 和 while 循 環 的區 別 在於: while 循 環 在條件 爲 真 時繼續執 行循 環 ,而 until 則 是在條件 爲 假 時繼續執 行循 環 。
Shell 還 提供了 true 和 false 兩條命令用於建立無限循 環結 構的需要,它 們 的返回狀 態 分 別 是 總爲 0 或 總爲 非 0
5.case 條件 選擇
if 條件 語 句用於在兩個 選項 中 選 定一 項 ,而 case 條件 選擇爲 用 戶 提供了根據字符串或 變 量的 值 從多個 選項 中 選擇 一 項 的方法,其格式如下:
case string in
exp-1)
若干個命令行 1
;;
exp-2)
若干個命令行 2
;;
……
*)
其他命令行
esac
shell 通 過計 算字符串 string 的 值 ,將其 結 果依次和表達式 exp-1 、 exp-2 等 進 行比 較 ,直到找到一個匹配的表達式 爲 止,如果找到了匹配 項則執 行它下面的命令直到遇到一 對 分號 ( ;; ) 爲 止。
在 case 表達式中也可以使用 shell 的通配符 (“*” 、 “ ? ” 、 “[ ]”) 。通常用 “*” 作 爲 case 命令的最後表達式以便使在前面找不到任何相 應 的匹配 項時執 行 “ 其他命令行 ” 的命令。
6. 無條件控制 語 句 break 和 continue
break 用於立即 終 止當前循 環 的 執 行,而 contiune 用於不 執 行循 環 中後面的 語 句而立即 開 始下一個循 環 的 執 行。 這 兩個 語 句只有放在 do 和 done 之 間 纔有效。
7. 函數定 義
在 shell 中 還 可以定 義 函數。函數 實際 上也是由若干條 shell 命令 組 成的,因此它與 shell 程序形式上是相似的,不同的是它不是一個 單 獨的 進 程,而是 shell 程序的一部分。函數定 義 的基本格式 爲 :
functionname
{
若干命令行
}
調 用函數的格式 爲 :
functionname param1 param2……
shell 函數可以完成某些例行的工作,而且 還 可以有自己的退出狀 態 ,因此函數也可以作 爲 if 、 while 等控制 結 構的條件。
在函數定 義時 不用 帶 參數 說 明,但在 調 用函數 時 可以 帶 有參數,此 時 shell 將把 這 些參數分 別賦 予相 應 的位置參數 $1 、 $2 、 ... 及 $* 。
8. 命令分 組
在 shell 中有兩 種 命令分 組 的方法: “()” 和 “{}” ,前者當 shell 執 行 () 中的命令 時 將再 創 建一個新的子 進 程,然後 這 個子 進 程去 執 行 圓 括弧中的命令。當用 戶 在 執 行某個命令 時 不想 讓 命令運行 時對 狀 態 集合 ( 如位置參數、 環 境 變 量、當前工作目 錄 等 ) 的改 變 影響到下面 語 句的 執 行 時 ,就 應該 把 這 些命令放在 圓 括弧中, 這樣 就能保 證 所有的改 變 只 對 子 進 程 產 生影響,而父 進 程不受任何干 擾 ; {} 用於將 順 序 執 行的命令的 輸 出 結 果用於另一個命令的 輸 入 ( 管道 方式 ) 。當我 們 要真正使用 圓 括弧和花括弧 時 ( 如 計 算表達式的 優 先 級 ) , 則 需要在其前面加上 轉義 符 (/) 以便 讓 shell 知道它 們 不是用於命令 執 行的控制所 用。
9. 信號
trap 命令用於在 shell 程序中捕捉到信號,之後可以有三 種 反 應 方式:
(1) 執 行一段程序來 處 理 這 一信號
(2) 接受信號的默 認 操作
(3) 忽 視這 一信號
trap 對 上面三 種 方式提供了三 種 基本形式:
第一 種 形式的 trap 命令在 shell 接收到 signal list 清 單 中數 值 相同的信號 時 ,將 執 行雙引號中的命令串。
trap 'commands' signal-list
trap "commands" signal-list
爲 了恢 復 信號的默 認 操作,使用第二 種 形式的 trap 命令:
trap signal-list
第三 種 形式的 trap 命令允 許 忽 視 信號:
trap " " signal-list
注意:
(1) 對 信號 11( 段 違 例 ) 不能捕捉,因 爲 shell 本身需要捕捉 該 信號去 進 行內存的 轉儲 。
(2) 在 trap 中可以定 義對 信號 0 的 處 理 ( 實際 上沒有 這 個信號 ) , shell 程序在其 終 止 ( 如 執 行 exit 語 句 ) 時發 出 該 信號。
(3) 在捕捉到 signal-list 中指定的信號並 執 行完相 應 的命令之後,如果 這 些命令沒有將 shell 程序 終 止的 話 , shell 程序將 繼續執 行收到信號 時 所 執 行的命令後面的命令, 這樣 將很容易 導 致 shell 程序無法 終 止。
另外,在 trap 語 句中, 單 引號和雙引號是不同的,當 shell 程序第一次碰到 trap 語 句 時 ,將把 commands 中的命令 掃 描一遍。此 時 若 commands 是用 單 引號括起來的 話 ,那 麼 shell 不會 對 commands 中的 變 量和命令 進 行替 換 ,否 則 commands 中的 變 量和命令將用當 時 具體 的 值 來替 換 。
五、運行 shell 程序的方法
用 戶 可以用任何 編輯 程序來 編 寫 shell 程序。因 爲 shell 程序是解 釋執 行的,所以不需要 編譯 裝配成目 標 程序,按照 shell 編 程的 慣 例,以 bash 爲 例,程序的第一行一般 爲 “# ! /bin/bash” ,其中 # 表示 該 行是注 釋 , 嘆 號 “ ! ” 告 訴 shell 運行 嘆 號之後的命令並用文件的其餘部分作 爲輸 入,也就是運行 /bin/bash 並 讓 /bin/bash 去 執 行 shell 程序的內容。
執 行 shell 程序的方法有三 種 :
(1)sh shell 程序文件名
這種 方法的命令格式 爲 :
bash shell 程序文件名
這實際 上是 調 用一個新的 bash 命令解 釋 程序,而把 shell 程序文件名作 爲 參數 傳遞給 它。新啓 動 的 shell 將去 讀 指定的文件, 執 行文件中列出的命令,當所有的命令都 執 行完 結 束。 該 方法的 優 點是可以利用 shell 調試 功能。
(2)sh
格式 爲 :
bash
這種 方式就是利用 輸 入重定向,使 shell 命令解 釋 程序的 輸 入取自指定的程序文件。
(3) 用chmod 命令使shell 程序成爲 可執 行的
一個文件能否運行取決於 該 文件的內容本身可 執 行且 該 文件具有 執 行 權 。 對 於 shell 程序,當用 編輯 器生成一個文件 時 ,系 統賦 予的 許 可 權 限都是 644(rw-r-r--) ,因此,當用 戶 需要運行 這 個文件 時 ,只需要直接 鍵 入文件名即可。
在 這 三 種 運行 shell 程序的方法中,最好按下面的方式 選擇 :當 剛 建立一個 shell 程序, 對 它的正確性 還 沒有把握 時 , 應 當使用第一 種 方式 進 行 調試 。當一個 shell 程序已 經調試 好 時 , 應 使用第三 種 方式把它固定下來,以後只要 鍵 入相 應 的文件名即可,並可被另一個程序所 調 用。
六、 bash 程序的 調試
在 編 程 過 程中 難 免會出 錯 ,有的 時 候, 調試 程序比 編 寫程序花 費 的 時間還 要多, shell 程序同 樣 如此。
shell 程序的 調試 主要是利用 bash 命令解 釋 程序的 選擇項 。 調 用 bash 的形式是:
bash - 選擇項 shell 程序文件名
幾個常用的 選擇項 是:
-e :如果一個命令失 敗 就立即退出
-n : 讀 入命令但是不 執 行它 們
-u :置 換時 把未 設 置的 變 量看作出 錯
-v :當 讀 入 shell 輸 入行 時 把它 們顯 示出來
-x : 執 行命令 時 把命令和它 們 的參數 顯 示出來
上面的所有 選項 也可以在 shell 程序內部用 “set - 選擇項 ” 的形式引用,而 “set + 選擇項 ” 則 將禁止 該選擇項 起作用。如果只想 對 程序的某一部分使用某些 選擇項時 , 則 可以將 該 部分用上面兩個 語 句包 圍 起來。
1. 未置 變 量退出和立即退出
未置 變 量退出特性允 許 用 戶對 所有 變 量 進 行 檢查 ,如果引用了一個未 賦值 的 變 量就 終 止 shell 程序 的 執 行。 shell 通常允 許 未置 變 量的使用,在 這種 情況下, 變 量的 值爲 空。如果 設 置了未置 變 量退出 選擇項 , 則 一旦使用了未置 變 量就 顯 示 錯誤 信息,並 終 止程 序的運行。未置 變 量退出 選擇項爲 “-u” 。
當 shell 運行 時 ,若遇到不存在或不可 執 行的命令、重定向失 敗 或命令非正常 結 束等情況 時 ,如果 未 經 重新定向, 該 出 錯 信息會打印在 終 端屏幕上,而 shell 程序仍將 繼續執 行。要想在 錯誤發 生 時 迫使 shell 程序立即 結 束,可以使用 “-e” 選項 將 shell 程序的 執 行立即 終 止。
2.shell 程序的跟蹤
調試 shell 程序的主要方法是利用 shell 命令解 釋 程序的 “-v” 或 “-x” 選項 來跟蹤程序 的 執 行。 “-v” 選擇項 使 shell 在 執 行程序的 過 程中,把它 讀 入的 每 一個命令行都 顯 示出來,而 “-x” 選擇項 使 shell 在 執 行程序的 過 程中把它 執 行的 每 一個命令在行首用一個 “+” 加上命令名 顯 示出來。並把 每 一個 變 量和 該變 量所取的 值 也 顯 示出來,因此,它 們 的主要區 別 在於:在 執 行命令行之前無 “-v” 則 打印出命令行的原始內容,而有 “-v” 則 打印出 經過 替 換 後的命令行的內容。
除了使用 shell 的 “-v” 和 “-x” 選擇項 以外, 還 可以在 shell 程序內部採取一些 輔 助 調 試 的措施。例如,可以在 shell 程序的一些 關鍵 地方使用 echo 命令把必要的信息 顯 示出來,它的作用相當於 C 語 言中的 printf 語 句, 這樣 就可以知道 程序運行到什 麼 地方及程序目前的狀 態 。
七、 bash 的內部命令
bash 命令解 釋 程序包含了一些內部命令。內部命令在目 錄 列表 時 是看不 見 的,它 們 由 shell 本身提供。常用的內部命令有: echo 、 eval 、 exec 、 export 、 readonly 、 read 、 shift 、 wait 和點 (.) 。下面 簡單 介 紹 其命令格式和功能。
1.echo
命令格式:echo arg
功能:在屏幕上打印出由arg 指定的字符串。
2.eval
命令格式:eval args
功能:當 shell 程序 執 行到 eval 語 句 時 , shell 讀 入參數 args ,並將它 們組 合成一個新的命令,然後 執 行。
3.exec
命令格式: exec 命令命令參數
功能:當 shell 執 行到 exec 語 句 時 ,不會去 創 建新的子 進 程,而是 轉 去 執 行指定的命令,當指定的命令 執 行完 時 , 該進 程,也就是最初的 shell 就 終 止了,所以 shell 程序中 exec 後面的 語 句將不再被 執 行。
4.export
命令格式: export 變 量名或: export 變 量名 = 變 量 值
功能: shell 可以用 export 把它的 變 量向下 帶 入子 shell 從而 讓 子 進 程 繼 承父 進 程中的 環 境 變 量。但子 shell 不能用 export 把它的 變 量向上 帶 入父 shell 。
注意:不 帶 任何 變 量名的 export 語 句將 顯 示出當前所有的 export 變 量。
5.readonly
命令格式: readonly 變 量名
功能:將一個用 戶 定 義 的 shell 變 量 標識爲 不可 變 的。不 帶 任何參數的 readonly 命令將 顯 示出所有隻 讀 的 shell 變 量。
6.read
命令格式:
read 變 量名錶
功能:從 標 準 輸 入 設備讀 入一行,分解成若干字, 賦值給 shell 程序內部定 義 的 變 量。
7.shift 語 句
功能: shift 語 句按如下方式重新命名所有的位置參數 變 量: $2 成 爲 $1 , $3 成 爲 $2…… 在程序中 每 使用一次 shift 語 句,都使所有的位置參數依次向左移 動 一個位置,並使位置參數 “$#” 減一,直到減到 0 。
8.wait
功能:是 shell 等待在後臺啓 動 的所有子 進 程 結 束。 Wait 的返回值總 是真。
9.exit
功能:退出shell 程序。在 exit 之後可有 選擇 地指定一個數字作 爲 返回狀 態 。
10.“.”( 點 )
命令格式: . Shell 程序文件名
功能:使shell 讀 入指定的shell 程序文件並依次執 行文件中的所有語 句。