天天看點

UNIX的Script

UNIX的Script

<<<目錄>>>

□前言

□将文字檔設為可執行的Shell Script

□Script的基本結構及觀念

□Bourne Shell

一、變數

二、執行指令

三、流程控制

□C Shell

□附錄A expr指令

□附錄B test指令

在DOS 中,你可能會從事一些例行的重覆性工作,此時你會将這些重覆性的指令寫

成批次檔,隻要執行這個批次檔就等於執行這些指令。大家會問在UNIX中是否有批次處

理這個東東,答案是有的。在UNIX中不隻有如DOS 的批次處理,它的功能比起DOS 更強

大,相對地也較複雜,已經和一般的高階語言不相上下。在UNIX中大家都不叫做批次檔

,而叫做Shell Script。

一般而言,Shell Script的地位和其它的可執行檔(或指令)是完全相同的,隻不

過Shell Script是以文字檔的方式儲存,而非二進位檔。而執行Shell Script時,必須

有一個程式将其内容轉成一道道的指令執行,而這個程式其實就是Shell ,這也就是為

什麽我們叫做Shell Script的原因(往後我們稱為Script)。不同Shell 的Script基本

上會有一些差異,是以我們不能将寫給A shell 的Script用B shell 執行。而在UNIX中

大家最常使用Bourne Shell以及C Shell ,是以這堂課就介紹這兩種Script的寫法。

如果我們已經寫好Script,如何将其設成可執行檔呢?因為Script其實是一個可執

行檔,是以必須将其存取權設定成可執行。我們可以使用下列指令更改存取權:

chmod u+x filename 隻有自己可以執行,其它人不能執行

chmod ug+x filename 隻有自己以及同一群可以執行,其它人不能執行

chmod +x filename 所有人都可以執行

而我們如何指定使用那一個Shell 來解釋所寫的Script呢?幾種基本的指定方式如

下所述:

1. 如果Script的第一個非空白字元不是"#",則它會使用Bourne Shell。

2. 如果Script的第一個非空白字元是"#"時,但不以"#!"開頭時,則它會使用C Shell。

3. 如果Script以"#!"開頭,則"#!"後面所寫的就是所使用的Shell,而且要将整個路徑

名稱指出來。

這裡建議使用第三種方式指定Shell ,以確定所執行的就是所要的。Bourne Shell的路

徑名稱為/bin/sh ,而C Shell 則為/bin/csh。

1. 使用Bourne Shell

┌——————————┐ ┌——————————┐

│echo enter filename │ │#!/bin/sh │

│ . │ or │ . │

│ . │ │ . │

└——————————┘ └——————————┘

2. 使用C Shell

│# C Shell Script │ │#!/bin/csh │

3. 使用/etc/perl

┌——————————┐

│#! /etc/perl │

│ . │

└——————————┘

除了在Script内指定所使用的Shell 外,你也可以在指令列中強制指定。比如你要

用C Shell 執行某個Script,你可以下這個指令:

csh filename

此時的Script的存取權就不一定要為可執行檔,其内部所指定的Shell 也會無效,詳細

的情形後面會讨論。

Script是以行為機關,我們所寫的Script會被分解成一行一行來執行。而每一行可

以是指令、注解、或是流程控制指令等。如果某一行尚未完成,可以在行末加上"\" ,

這個時候下一行的内容就會接到這一行的後面,成為同一行,如下

┌———————————┐

│echo The message is \ │

│too long so we have \ │

│to split it into \ │

│several lines │

└———————————┘

當Script中出現"#" 時,再它後面的同一行文字即為注解,Shell 不會對其翻譯。

在Script中要執行一個指令的方法和在指令列中一樣,你可以前景或背景執行,執

行指令時也會需要設定一些環境變數。

Script的流程控制和一般高階語言的流程控制沒有什麽兩樣,也和高階語言一樣有

副程式。這些使得Script的功能更加強大。

為了達到與高階語言相同的效果,我們也可以在Script中設定變數,如此使Script

成為一個名付其實的高階語言。

Bourne Shell的變數型态隻有字串變數,是以要使用數值運算則必須靠外部指令達

成目的。而其變數種類有下列幾種:

1. 使用者變數

這是最常使用的變數,我們可以任何不包含空白字元的字串來當做變數名稱。

設定變數值時則用下列方式:

var=string

取用變數時則在變數名稱前加上一"$" 号。

┌———————┐

│name=Tom │

│echo name │

│echo $name │

└———————┘

結果如下:

name

Tom

2. 系統變數(環境變數)

和使用者變數相似,隻不過此種變數會将其值傳給其所執行的指令。要将一使

用者變數設定為系統變數,隻要加上:

export var

│export name │

以下是使用者一進入系統之後就已設定好的系統變數:

$HOME 使用者自己的目錄

$PATH 執行指令時所搜尋的目錄

$TZ 時區

$MAILCHECK 每隔多少秒檢查是否有新的信件

$PS1 在指令列時的提示号

$PS2 當指令尚未打完時,Shell 要求再輸入時的提示号

$MANPATH man 指令的搜尋路徑

3. 唯讀的使用者變數

和使用者變數相似,隻不過這些變數不能被改變。要将使用者變數設成唯讀的

,隻要加上:

readonly var

而若隻打readonly則會列出所有唯讀的變數。還有一點,系統變數不可以設定

成唯讀的。

│readonly name │

│name=John │

│readonly │

name: is read only

readonly name

readonly ......

4. 特殊變數

有些變數是一開始執行Script時就會設定,并且不以加以修改,但我們不叫它

唯讀的系統變數,而叫它特殊變數(有些書會叫它唯讀的系統變數),因為這

些變數是一執行程式時就有了,況且使用者無法将一般的系統變數設定成唯讀

的。以下是一些等殊變數:

$0 這個程式的執行名字

$n 這個程式的第n個參數值,n=1..9

$* 這個程式的所有參數

$# 這個程式的參數個數

$$ 這個程式的PID

$! 執行上一個背景指令的PID

$? 執行上一個指令的傳回值

當你執行這個程式時的參數數目超過9 個時,我們可以使用shift 指令将參數

往前移一格,如此即可使用第10個以後的參數。除此之外,吾人可以用set 命

令改變$n及$*,方法如下:

set string

如此$*的值即為string,而分解後則會放入$n。如果set 指令後面沒有參數,

則會列出所有已經設定的變數以及其值。

檔名:ex1 參數:this is a test

│echo Filename: $0 │

│echo Arguments: $* │

│echo No. of args.: $# │

│echo 2nd arg.: $2 │

│shift │

│set hello, everyone │

Filename: ex1

Arguments: this is a test

No. of args.: 4

2nd arg.: is

No. of args.: 3

2nd arg.: a

Arguments: hello, everyone

2nd arg.: everyone

值得一提的是,當你想從鍵盤輸入一變數值時,你可以使用下面的指令:

read var1 var2.....

這時read會将一個字分給一個變數。如果輸入的字比變數還多,最後一個變數會将

剩下的字當成其值。如果輸入的字比變數還少,則後面的變數會設成空字串。

如果需要處理數值運算,我們可以使用expr指令。其參數及輸出列於附錄A。

在Bourne Shell中有五種方法執行一個指令,而這五種方式所産生的果有些許的不

同。

1. 直接下指令

這個方式和在指令列中直接下指令的效果一樣。

2. 使用sh指令

sh command

這個檔案必須是Bourne Shell的Script,但這個檔案并不一定要設成可執行。

除此之外和直接下指令的方式一樣。

3. 使用"."指令

. command

這時和使用sh指令相似,隻不過它不像sh一般會産生新的process ,相反地,

它會在原有的process 下完成工作。

4. 使用exec指令

exec command

此時這個Script将會被所執行的指令所取代。當這個指令執行完畢之後,這個

Script也會随之結束。

5. 使用指令替換

這是一個相當有用的方法。如果想要使某個指令的輸出成為另一個指令的參數

時,就一定要使用這個方法。我們将指令列於兩個"`" 号之間,而Shell 會以

這個指令執行後的輸出結果代替這個指令以及兩個"`" 符号。

str='Current directory is '`pwd`

echo $str

Current directory is /users/cc/mgtsai

這個意思是pwd 這個指令輸出"/users/cc/mgtsai",而後整個字串代替原

來的`pwd` 設定str 變數,是以str 變數的内容則會有pwd 指令的輸出。

number=`expr $number + 1`

這就是先前所提要作數值運算的方法,基本上expr指令隻将運算式解,而

後輸出到标準輸出上。如果要将某變數設定成其值,非得靠指令替換的方

式不可。這個例子是将number變數的值加1 後再存回number變數。

在介紹流程控制之前,我們先來看看test指令。test指令的參數是條件判斷式,當

條件為真時則傳回非零值,而條件為僞時則傳回零。在所有的流程控制都必須用到

test指令來判斷真僞。而test指令的使用方法則列於附錄B。

test $# = 0

如果執行這個程式沒有參數時,會傳回非零值代表"$# = 0"這個條件成立。反

之則會傳回零。

以下介紹各種流程控制:

1. if then

文法以及流程圖如下

│ FALSE

if (condition) <condition>—┐

then │TRUE │

then-commands then-commands │

fi ├————┘

condition 是一個test指令。往後所介紹的各種流程中的condition 都是test

指令。

檔名:chkarg

│if (test $# != 0) │

│ then │

│ echo Arg1: $1 │

│fi │

$ chkarg Hello

Arg1: Hello

$ chkarg

$

2. if then else

if (condition) <condition>—————┐

then-commands then-commands else-commands

else ├————————┘

else-commands │

fi

3. if then elif

if (condition1) <condition1>—┐

then │TRUE │ FALSE

commands1 commands1 <condition2>—┐

elif (condition2) │ │TRUE │

then │ commands2 commands3

commands2 ├—————┴————┘

else │

commands3

echo 'word 1: \c'

read word1

echo 'word 2: \c'

read word2

echo 'word 3: \c'

read word3

if (test "$word1" = "$word2" -a "$word2" = "$word3")

then

echo 'Match: words 1, 2, & 3'

elif (test "$word1" = "$word2")

echo 'Match: words 1 & 2'

elif (test "$word1" = "$word3")

echo 'Match: words 1 & 3'

elif (test "$word2" = "$word3")

echo 'Match: words 2 & 3'

else

echo 'No match'

4. for in

for var in arg-list ┌—<arg-list還有東西嗎?>—┐

do │ │TRUE │

commands │ 從arg-list取得一項 │

done │ 放到變數var │

│ │ │

│ commands │

└——————┘ │

┌———————————┐ ┌———————┘

│for a in xx yy zz │ │

│ do │

│ echo $a │

│done │

xx

yy

zz

5. for

for var ┌—<參數中還有東西嗎?>—┐

commands │ 從參數中取得一項 │

└—————┘ │

檔名:lstarg ┌———————┘

┌———————————┐ │

│for a │

$lstarg xx yy zz

6. while

while (condition) ┌—<condition>—┐

commands │ commands │

done └————┘ │

┌————┘

┌———————————————┐

│number=0 │

│while (test $number -lt 10) │

│ echo "$number\c" │

│ number=`expr $number + 1` │

│echo │

└———————————————┘

0123456789

7. until

│ TRUE

until (condition) ┌—<condition>—┐

do │ │FALSE │

它和while 的不同隻在於while 是在條件為真時執行回圈,而until 是在條件

為假時執行回圈。

8. break及continue

這兩者是用於for, while, until 等回圈控制下。break 會跳至done後方執行

,而continue會跳至done執行,繼續執行回圈。

9. case

case str in <str=pat1>————commands1—┐

pat1) commands1;; │FALSE TRUE │

pat2) commands2;; <str=pat2>————commands2—┤

pat3) commands3;; │FALSE TRUE │

esac <str=pat3>————commands3—┤

│FALSE │

├————————————┘

而pat 除了可以指定一些确定的字串,也可以指定字串的集合,如下

* 任意字串

? 任意字元

[abc] a, b, 或c三字元其中之一

[a-n] 從a到n的任一字元

| 多重選擇

│echo 'Enter A, B, or C: \c' │

│read letter │

│case $letter in │

│ A|a) echo 'You entered A.';;│

│ B|b) echo 'You entered B.';;│

│ C|c) echo 'You entered C.';;│

│ *) echo 'Not A, B, or C';; │

│esac │

10. 函數

格式如下

function-name()

{

commands

}

而要呼叫此函數,就像在指令列下直接下指令一般。

C Shell 有些特性和Bourne Shell一樣,但有些不相同。這裡介紹與Bourne Shell

不相同的地方。

1. 字串變數

這個部分和Bourne Shell的變數一樣,隻不過在設定變數值時不能使用Bourne

Shell的方式,而必須打:

set var=value

2. 數字運算

基本上C Shell 沒有數字變數,但C Shell 卻有簡單的方法處理數字運算:

@ var operator expression

operator可以是C 語言中的=, +=, -=,......,而expression則是運算式。運

算式的運算子如下:

A. () 改變計算的順序

~@

B. ~ 位元NOT運算

@~~

! 邏輯否定

C. % 取馀數

/ 除

* 乘

- 減

+ 加

D. >> 右移

<< 左移

E. > 大於

< 小於

>= 大於等於

<= 小於等於

!= 不等於

== 等於

F. & 位元AND運算

^ 位元XOR運算

| 位元OR 運算

G. && 邏輯AND

|| 邏輯OR

除此之外,我們也可以檢驗一個檔案的狀态,如下

-n filename

而-n可為下列之一

-d 檔案是一個目錄檔案

-e 檔案存在

-f 檔案為一般的檔案

-o 使用者擁有這個檔案

-r 使用者可以讀取這個檔案

-w 使用者可以寫入這個檔案

-x 使用者可以執行這個檔案

-z 檔案長度為0

@ count = count + 1

@ flag = -e /users/cc/mgtsai/mail && -e /usr/spool/mail

3. 陣列

在C Shell 中,我們可以宣告陣列變數,方式如下

set var=(val1 val2 ......)

而var[1]之值為val1,var[2]之值為val2......。而$var代表整個陣列。我們

可以用$#var 來計算陣列個數,也可以用$?var 來檢查某個變數是否已宣告。

$argv 和Bourne Shell的$*相似,隻不過這是一個陣列。

$argv[n] 和Bourne Shell的$n相同,但不受個數限制。

$#argv 和Bourne Shell的$#相同

$home 和Bourne Shell的$HOME相同

$path 和Bourne Shell的$PATH相似,隻不過這是一個陣列

$prompt 和Bourne Shell的$PS1相同

$shell Shell的路徑名稱

$status 和Bourne Shell的$?相同

$$ 和Bourne Shell的$$相同

$< 鍵盤輸入

基本上和Bourne Shell相同,隻有一點在Bourne Shell中的"." 指令在C Shell 中

則為"source"指令。

在C Shell 中流程控制不像Bourne Shell中一般需要使用test指令。相反地,它和

C 語言類似隻要在條件中寫出運□式即可。當運算結果不為零時,其值為真,為零

時其值為僞。以下是C Shell的流程控制

1. if

文法如下

if (expression) simple-command

2. goto

goto label

這時程式會跳至以l"label:"開頭的那一行執行

if ($#argv == 2) goto goodargs

echo 'Please use two arguments.'

exit

goodrags:

...

3. if then else

這和Bourne Shell的if then, if then else, if then elif 相似。文法如下

A. if (expression) then

endif

B. if (expression) then

C. if (expression) then

else if (expression) then

4. foreach

這和Bourne Shell的for in相似。文法如下

foreach var (arg-list)

end

5. while

這和Bourne Shell的while相似。文法如下

while (expression)

6. break及continue

這和Bourne Shell的break 及continue相似,是用來中斷foreach 及while 回

圈。

7. switch

這和Bourne Shell的case相似。文法如下

switch (string)

case pat1:

commands1

breaksw

case pat2:

commands2

case pat3:

endsw

指令格式

expr expression

叙述

expression是由字串以及運算子所組成,每個字串或是運算子之間必須用空白隔開

。下表是運算子的種類及功能,而優先順序則以先後次序排列,我們可以利用小括

号來改變運算的優先次序。其運算結果則輸出至标準輸出上。

: 字串比較。比較的方式是以兩字串的第一個字母開始,而以第二個字串的

字母結束。如果相同時,則輸出第二個字串的字母個數,如果不同時則傳

回0 。

* 乘法

/ 除法

% 取馀數

+ 加法

- 減法

= 等於

> 大於

& AND運算

| OR運算

當expression中含有"*", "(", ")" 等符号時,必須在其前面加上"\" ,以免被

Shell 解釋成其它意義。

expr 2 \* \( 3 + 4 \) 其輸出為14

test expression

expression中包含一個以上的判斷準則以作為test評诂的标準。兩準則間用"-a"代

表邏輯AND 運算,"-o"代表邏輯OR運算,而在準則前放置一"!" 代表NOT 運算。如

果沒有括号,則優先權則為"!" > "-a" > "-o" 。和expr指令相同,相使用左右括

号時,必須在其前面加上"\" 。以下是有關準則的叙述(合叙述時傳回真,否則傳

回僞):

string string不為空白字串

-n string string的長度大於0

-z string string的長度等於0

string1=string2 string1等於string2

string1!=string2 string1不等於string2

int1 -gt int2 int1大於int2

int1 -ge int2 int1大於等於int2

int1 -eq int2 int1等於int2

int1 -ne int2 int1不等於int2

int1 -le int2 int1小於等於int2

int1 -lt int2 int1小於int2

-r filename 檔案可讀取

-w filename 檔案可寫入

-x filename 檔案可執行

-f filename 檔案為一般檔

-d filename 檔案為目錄

-s filename 檔案為非空的一般檔

test -r "$filename" -a -s "$filename"

本站文章僅代表作者觀點,本站僅傳遞資訊,并不表示贊同或反對.轉載本站點内容時請注明來自[url]www.linuxeden.com[/url]-Linux伊甸園。如不注明,[url]www.linuxeden.com[/url]将根據《網際網路著作權行政保護辦法》追究其相應法律責任。