Unix系列shell程序編寫從入門到精通(上)

*Shell 是什麼 ?
任何發明都具備供用戶使用的界面。 UNIX 供用戶使用的界面就是 Shell(DOS command 熟悉吧,但 UNIX 的要強大的多 ) Shell 爲用戶提供了輸入命令和參數並可獲得命令執行結果的環境。

爲了避免同的須要, UNIX 提供了不一樣的 Shell 。如今的 UNIX 大部分都支持 BourneShell ,如下教程就以 BourneShell(Bsh) 爲例,一步步的領略 UNIX Shell 的強大功能,佔先其強大魅力,達到更方便靈活的管理、應用 UNIX 的目的。

1.UNIX 內核和 Shell 的交互方法

啓動 UNIX 時,程序 UNIX( 內核 ) 將被調入計算機內存,並一直保留在內存中直到機器關閉。在引導過程當中,程序 init 將進入後臺運行一直到機器關閉。該程序查詢文件 /etc/inittab ,該文件列出了鏈接終端的各個端口及其特徵。當發現一個活動的終端時, init 程序調用 getty 程序在終端上顯示 login 等登錄信息。 (username passwd) ,在輸入密碼後, getty 調用 login 進程,該進程根據文件 /etc/passwd 的內容來驗證用戶的身份。若用戶經過身份驗證, login 進程 把用戶的 home 目錄設置成當前目錄並把控制交給一系列 setup 程序。 setup 程序能夠是指定的應用程序,一般 setup 程序 爲一個 Shell 程序,如 :/bin/sh Bourne Shell command 出來了,呵呵)。

獲得控制後, Shell 程序讀取並執行文件 /etc/.profile 以及 .profile 。這兩個文件分別創建了系統範圍內的和 該用戶本身的工做環境。最後 Shell 顯示命令提示符,如 $ ( 這是以 bsh 爲例,如果 csh, .cshrc,ksh .kshrc,bash .bashrc 等等 )

:( 不妨把 /etc/.profile .profile 當作 DOS autoexec.bat config.sys 文件 )

shell 退出時,內核把控制交給 init 程序 , 該程序從新啓動自動登錄過程。有兩種方法使 shell 退出,一是用戶執行 exit 命令,二是 內核 ( 例如 root kill 命令 ) 發出一個 kill 命令結束 shell 進程。 shell 退出後,內核回收用戶及程序使用的資源。

用戶登錄後,用戶命令同計算機交互的關係爲 : 命令進程 --->Shell 程序 --->UNIX 內核 ---> 計算機硬件。當用戶輸入一個命令,如 $ls, Shell 將定位其可執行文件 /bin/ls 並把其傳遞給內核執行。內核產生一個新的子進程調用並執行 /bin/ls 。當程序執行完畢後,內核取消 該子進程並把控制交給其父進程,即 Shell 程序。例如執行 :

$ps

該命令將會列出用戶正在執行的進程,即 Shell 程序 ( 下來詳細說說,別急如今 ) ps 程序。若執行 :

$sleep 10 &
$ps

其中第一條命令將產生一個在後臺執行的 sleep 子進程。 ps 命令執行時會顯示出該子進程。

每當用戶執行一條命令時,就會產生一個子進程。該子進程的執行與其父進程或 Shell 徹底無關,這樣可使 Shell 去作其餘工做。 (Shell 只是把用戶的意圖告訴內核,而後該幹嗎幹嗎 :)) 如今 windows 有個計劃任務 ( 在固定的時間,日期自動執行某任務 ), 其實 UNIX 很早就有這個功能了,也就是所謂的 Shell 的自動執行。一些 UNIX 資源,如 cron 能夠自動執行 Shell 程序而無需用戶的參與, ( 這個功能好象在 /var/spool/crotab 目錄裏 )

Crontab 程序對於系統管理員來講是很是有用的。 Cron 服務用於計劃程序在特定時間(月、日、周、時、分)運行。咱們以 root crontab 爲例。根用戶的 crontab 文件放在 /var/spool/crontab/root 中,其格式以下:

(1) (2) (3) (4) (5) (6)
0 * * 3 /usr/bin/updatedb
1. 分鐘 (0-60)
2. 小時 (0-23)
3. (1-31)
4. (1-12)
5. 星期 (1-7)
6. 所要運行的程序
2.Shell 的功能和特色
1> 命令行解釋
2> 使用保留字
3> 使用 Shell 元字符 ( 通配符 )
4> 可處理程序命令
5> 使用輸入輸出重定向和管道
6> 維護一些變量
7> 運行環境控制
8> 支持 Shell 編程

對於命令行解釋就很少說了,就是在 shell 提示符 ( 例如 :$,%,# ) 後輸入一行 unix 命令, Shell 將接收用戶的輸入。

使用保留字 :Shell 有一些具備特殊意義的字,例如在 Shell 腳本中, do,done,for 等字用來控制循環操做, if,then 等控制條件操做。 保留字隨 Shell 環境的不一樣而不一樣。

通配符: * 匹配任何位置
? 匹配單個字符
[] 匹配的字符範圍或列表 例如 :

$ls [a-c]*

將列出以 a-c 範圍內字符開頭的全部文件
$ls [a,m,t]*
將列出以 e,m t 開頭的全部文件

程序命令 :當用戶輸入命令後, Shell 讀取環境變量 $path( 通常在用戶本身的 .profile 中設置 ) ,該變量包含了命令可執行文件可能存在的目錄列表。 shell 從這些目錄中尋找命令所對應的可執行文件,而後將該文件送給內核執行。

輸入輸出重定向及管道 :重定向的功能同 DOS 的重定向功能:

> 重定向輸出
< 重定向輸入

而管道符號,是 unix 功能強大的一個地方 , 符號是一條豎線 :| ,用法 : command 1 | command 2 他的功能是把第一個命令 command 1 執行的結果做爲 command 2 的輸入傳給 command 2 ,例如 :

$ls -s|sort -nr|pg

該命令列出當前目錄中的全部文件,並把輸出送給 sort 命令做爲輸入, sort 命令按數字遞減的順序把 ls 的輸出排序。而後把排序後的 內容傳送給 pg 命令, pg 命令在顯示器上顯示 sort 命令排序後的內容。

維護變量 Shell 能夠維護一些變量。變量中存放一些數據供之後使用。用戶能夠用 = 給變量賦值,如 :

$lookup=/usr/mydir

該命令創建一個名爲 lookup 的變量並給其賦值 /usr/mydir, 之後用戶能夠在命令行中使用 lookup 來代替 /usr/mydir ,例如 :
$echo $lookup
結果顯示 :/usr/mydir

爲了使變量能被子進程使用 , 可用 exprot 命令,例如 :

$lookup=/usr/mydir
$export lookup

運行環境控制 :當用戶登錄啓動 shell 後, shell 要爲用戶建立一個工做的環境,以下 :

1> login 程序激活用戶 shell 後,將爲用戶創建環境變量。從 /etc/profile .profile 文件中讀出,在這些文件中通常都用 $TERM 變量設置終端類型,用 $PATH 變量設置 Shell 尋找可執行文件的路徑。

2> /etc/passwd 文件或命令行啓動 shell 時,用戶能夠給 shell 程序指定一些參數,例如 -x ,能夠在命令執行前顯示該命令及其參數。後面詳細介紹這些參數。

shell 編程 :本文主要介紹的內容。

shell 自己也是一種語言 (* 能夠先理解爲 unix 命令的組合,加上類 C 的條件,循環等程序控制語句 , 相似 dos 批處理,但要強大的多 ), 用戶能夠 經過 shell 編程 ( 腳本 , 文本文件 ) ,完成特定的工做。

SHELL 變量

下面咱們詳細的介紹 Bourne Shell 的編程 :

自從貝爾實驗室設計了 Bourne Shell 。從那時起許多廠商根據不一樣的硬件平臺設計了許多版本得 unix 。但在衆多版本的 unix 中, Bourne Shell 一直保持一致。
1>Bsh 的啓動:用戶在登錄後,系統根據文件 /etc/passwd 中有關該用戶的信息項啓動 Shell 。例如某用戶在 passwd 的信息項爲 :

ice_walk:!:411:103:Imsnow ,ice_walk:/home/ice_walk:/bin/bsh

則代表,用戶名是 ice_walk 等信息,在最後一項 /bin/bsh 代表用戶的 sh 環境類型是 bsh, 因而系統啓動之。在啓動或執行 ( 包括下面咱們要講 shell 程序 -- 腳本)過程當中可使用如下一些參數,咱們一一說明 :

-a 將全部變量輸出
-c string string 中讀取命令
-e 使用非交互式模式
-f 禁止 shell 文件名產生
-h 定義
-i 交互式模式
-k 爲命令的執行設置選項
-n 讀取命令但不執行
-r 受限模式
-s 命令從標準輸入讀取
-t 執行一命令,而後退出 shell
-u 在替換時,使用未設置的變量將會出錯
-v 顯示 shell 的輸入行
-x 跟蹤模式,顯示執行的命令

許多模式能夠組合起來用 , 您能夠試試了,但 -ei 好象不行,你說 why 呢?

使用 set 能夠設置或取消 shell 的選項來改變 shell 環境。打開選項用 -, 關閉選項用 +, 多數 unix 容許打開或關閉 a f e h k n u v x 選項。若顯示 Shell 中已經設置的選項,執行 :

$echo $-

Bsh 中每一個用戶的 home 目錄下都有一個 .profile 文件,能夠修改該文件來修改 shell 環境。爲了增長一個可執行文件的路徑 ( 例如 /ice_walk/bin) 能夠把下面代碼加入 .profile

PATH=$PATH:/ice_walk/bin;exprot PATH

.profile shell 的環境變量意思以下 :

CDPATH 執行 cd 命令時使用的搜索路徑
HOME 用戶的 home 目錄
IFS 內部的域分割符,通常爲空格符、製表符、或換行符
MAIL 指定特定文件 ( 信箱 ) 的路徑,有 UNIX 郵件系統使用
PATH 尋找命令的搜索路徑 ( dos config.sys path)
PS1 主命令提示符,默認是 $
PS2 從命令提示符,默認是 >
TERM 使用終端類型

2>Bsh 裏特殊字符及其含義

Bsh 中有一組非字母字符。這些字符的用途分爲四類 : 做爲特殊變量名、產生文件名、數據或程序控制以及引用和逃逸字符控制。他們 可讓用戶在 Shell 中使用最少的代碼完成複雜的任務。

*> Shell 變量名使用的特殊字符
$# 傳送給命令 Shell 的參數序號
$- Shell 啓動或使用 set 命令時提供選項
$? 上一條命令執行後返回的值
$$ 當前 shell 的進程號
$! 上一個子進程的進程號
$@ 全部的參數,每一個都用雙括號括起
$* 全部參數,用雙括號括起
$n 位置參數值, n 表示位置
$0 當前 shell
*> 產生文件名的特殊字符
包括 *,?,[] ,上面講過,再也不多說。
*> 數據或程序控制使用的特殊字符
>(file) 輸出重定向到文件中 ( 沒有文件則建立,有則覆蓋 )
>>(file) 輸出重定向到文件中 ( 沒有則建立,有則追加到文件尾部 )
<(file) 輸入重定向到文件
; 命令分割符
| 管道符
& 後臺運行 ( 例如 :sleep 10 &)
` ` 命令替換,重定向一條命令的輸出做爲另外一命令的參數
*> 對於引用或逃逸的特殊字符

Bsh 用單引號 ' ' 和雙引號 將特殊字符或由空白分隔的字引用起來組成一個簡單的數據串 . 使用單引號和雙引號的區別是雙引號中的內容可進行參數和變量替換 . 逃逸字符也同樣 .

$echo $HOME $PATH
結果顯示 $/u/ice_walk/bin:/etc:/usr/bin
$echo '$HOME $PATH' 結果顯示 $HOME $PATH

shell 的逃逸符是一個 \\, 表示其後的字符不具備特殊的含義或不是 shell 的函數

$echo \\$HOME $PATH
結果顯 $$HOME /bin:/etc:/usr/bin:

3>Bsh 的變量

前面咱們在多個地方引用了變量 , Shell 遇到一個 $ 符時 ( 沒有被引用或逃逸 ) ,它將認爲其後爲一變量。不論該變量是環境變量仍是用戶自定義的變量,在命令行中變量名要被變量值替換。例如命令 :ls $HOME 將列出變量 HOME 對應目錄下的文件。 用戶能夠在命令行中的任何地方進行變量替換。包括命令名自己,例如:

$dir=ls
$$dir f*

將列出以 f 開頭的文件。

如今詳細的介紹下 Bsh 的變量。 Bsh 中有四類變量 : 用戶定義的變量、位置變量 (shell 參數 ) 、預約義變量及環境變量。

用戶定義的變量:

用戶定義的變量由字母和下劃線組成,而且變量名的第一個字符不能爲數字 (0~9) 。與其餘 UNIX 名字同樣,變量名是大小寫敏感的。用戶能夠在命令行上用 = 給變量賦值,例如 :

$NAME=ice_walk

給變量 NAME 賦值爲 ice_walk, 在應用變量 NAME 的時候,在 NAME 前加 $ 便可,前面已說,再也不廢話 ( 別說我廢話多,關鍵是沒當過老師 :() 。能夠用變量和其餘字符組成新的字,例如 :

$SUN=sun
$echo ${SUN}day

在應用 shell 變量時候,能夠在變量名字兩邊 $ 後面加上 {} ,以更加清楚的顯示給 shell, 哪一個是真正的變量,以實現字符串的合併等功能。

結果顯示 :sunday( 注意不能 echo $SUNday, 由於 SUNday 變量沒定義,讀者試下執行結果 ) 用戶也能夠在命令行上同時對多個變量賦值,賦值語句之間用空格分開 :

$X=x Y=y

注意變量賦值是從右到左進行的

$X=$Y Y=y
X 的值是 y
$X=z Y=$Z

Y 的值是空 ( 變量未賦值時, shell 不報錯,而是賦值爲空 )

用戶可使用 unset < 變量 > 命令清除給變量賦的值

用戶使用變量時要在其前面加一 $ 符,使變量名被變量值所替換。 Bsh 能夠進行變量的條件替換,即只有某種條件發生時才進行替換。替換條件放在一對大括號 {} 中,如 :

${variable: -value} variable 是一變量值, value 是變量替換使用的默認值

$echo Hello $UNAME
結果顯示 :Hello
$echo Hello ${UNAME: -there}
結果顯示 :Hello there
$echo $UNAME
結果顯示 : ( )
$UNAME=John
$echo Hello ${UNAME: -there}
結果顯示 :Hello John

能夠看出,變量替換時將使用命令行中定義的默認值,但變量的值並無所以而改變。另一種替換的方法是不但使用默認值進行替換,並且將默認值賦給該變量。其形式以下 :

${variable:=value}

該形式在變量替換後同時把值 value 符給變量 variable

$echo Hello $UNAME
結果顯示 :Hello
$echo Hello ${UNAME:=there}
結果顯示 :Hello there
$echo $UNAME
結果顯示 :there
$UNAME=John
$echo Hello ${UNAME:-there}
結果顯示 :Hello John

變量替換的值也能夠是 ` ` 括起來的命令 :

$USERDIR={$Mydir: -`pwd`}

第三種變量的替換方法是隻有當變量已賦值時才用指定值替換形式 :

${variable: +value}

只有變量 variable 已賦值時,其值才用 value 替換,不然不進行任何替換,例如 :

$ERROPT=A
$echo ${ERROPT: +Error tracking is acitive}
結果顯示 :Error tracking is acitive
$ERROPT=
$echo ${ERROPT: +Error tracking is acitive}
結果顯示 : ( )

咱們還可使用錯誤檢查的條件進行變量替換 :

${variable:?message}

當變量 variable 已設置時,正常替換。不然消息 message 將送到標準錯誤輸出 ( 若此替換出如今 shell 程序中 , 那麼該程序將終止 ) 。 例如:

$UNAME=
$echo $ {UNAME:?UNAME HAS NOT BEEN SET}
結果顯示 :UNAME HAS NOT BEEN SET

$UNAME=Stephanie
$echo $ {UNAME:?UNAME HAS NOT BEEN SET}

結果顯示 :Stephanie
當沒有指定 message 時, shell 將顯示一條默認的消息,例如 :

$UNAME=
$echo $ {UNAME:?}
結果顯示 :sh:UNAME:parameter null or not set

4> 位置變量或 Shell 參數

shell 解釋用戶的命令時,將把命令行的第一個字做爲命令,而其餘的字做爲參數。當命令對應的可執行文件爲 Shell 程序時,這些參數將做爲位置變量傳送給該程序。第一個參數記爲 $1, 第二個爲 $2.... 第九個爲 $9 。其中 1 9 是真正的參數名, $ 符只是用來標識變量的替換。

位置變量 $0 指命令對應的可執行文件名。在後面將詳細介紹位置變量。

1. 只讀變量

用戶將變量賦值後,爲了防止之後對該變量的修改,能夠用如下命令將該變量設置爲只讀變量:

readonly variable

2.export 命令

shell 執行一個程序時,首先爲該程序創建一個新的執行環境,稱爲子 shell 。在 Bourne Shell 中變量都是局部的,即他們只在建立他們的 Shell 中有意義。用戶能夠用 export 命令讓變量被其餘子 Shell 識別。但某用戶的變量是無法讓其餘用戶使用的。

當用戶啓動一個新 shell , shell 將使用默認的提示符。由於賦給變量 PS1 的值只在當前 shell 中有效。爲了讓子 Shell 使用當前 Shell 中定義的提示符號,可使用 export 命令:

$PS1=Enter command:
Enter command:export PS1
Enter command:sh
Enter command:

此時變量 PS1 變成了全局變量。它能夠被其子 Shell 使用。當變量被設置成全局的之後,將一直保持有效直到用戶退出該變量所在的 Shell 。用戶能夠在文件 .profile 中給一個變量永久賦值。詳見規範 Shell

基本語句

從本節起,咱們將詳細介紹 Shell 程序設計的基本知識,經過編寫 Shell 腳本,用戶能夠根據本身的須要有條件的或者重複的執行命令。經過 Shell 程序,能夠把單個的 UNIX 命令組合成一個徹底實用的工具,完成用戶的任務。

1> 什麼是 Shell 程序

當用戶在 UNIX Shell 中輸入了一條複雜的命令,如 :

$ls -R /|greo myname |pg

咱們能夠稱用戶在對 Shell 編程,當把這條語句寫在一個文件裏,而且符給該文件可執行權限,那麼該文件就是咱們傳統上說的 Shell 程序。

2> 簡單的 Shell 程序

假設用戶天天使用下述命令備份本身的數據文件 :

$cd /usr/icewalk;ls * |cpio -o > /dev/fd0

咱們能夠把它寫在一個文件,如 :ba.sh :

$cat >ba.sh
cd /usr/icewalk
ls * |cpio -o > /dev/fd0
^D (ctrl_d)

程序 ba.sh 就是 Shell 腳本,用戶能夠用 vi 或其餘編輯工具編寫更復雜的腳本。

此時用戶備份文件只須要執行 Shell 程序 ba.sh, 執行時需在當前 Shell 中建立一個子 Shell:

$sh ba.sh

程序 sh 與用戶登錄時執行的 Bourne Shell 相同,但當 Sh 命令帶參數 ba.sh 後,它將再也不是一個交互式的 Shell ,而是直接從文件 ba.sh 中讀取命令。

執行 ba.sh 中命令的另外一方法是給文件 ba.sh 執行權限:

$chmod +x ba.sh

此時,用戶能夠輸入文件名 ba.sh 作爲一個命令來備份本身的數據,須要注意的是,用這種方法執行命令的時候,文件 ba.sh 必須存在於環境變量 $PATH 所指定的路徑上
相關文章
相關標籤/搜索