Bourne Shell及shell程式設計(轉)

post0發表於2007-08-11
Bourne Shell及shell程式設計(轉)[@more@]

(文:何斌武)

Bourne Shell

介紹:Bourne Shell 基礎及其他很多有用的特性,shell程式設計及組織。

主要內容:

.shell基礎 基本介紹,環境,選項,特殊字元

.shell變數 使用者定義變數,環境變數,位置變數(shell 引數)

.shell script程式設計

條件測試,迴圈及重複控制

.shell定製

1.shell基礎知識

作者:Stephen Bourne 在Bell實驗室開發

建議:man sh 檢視相關UNIX上的改進或特性

(1)shell提示符及其環境

/etc/passwd檔案

提示符:$

/etc/profile $HOME/.profile

(2)shell執行選項

-n 測試shell script語法結構,只讀取shell script但不執行

-x 進入跟蹤方式,顯示所執行的每一條命令,用於排程

-a Tag all variables for export

-c "string" 從strings中讀取命令

-e 非互動方式

-f 關閉shell檔名產生功能

-h locate and remember functions as defind

-i 互動方式

-k 從環境變數中讀取命令的引數

-r 限制方式

-s 從標準輸入讀取命令

-t 執行命令後退出(shell exits)

-u 在替換中如使用未定義變數為錯誤

-v verbose,顯示shell輸入行

這些選項可以聯合使用,但有些顯然相互衝突,如-e和-i.

(3)受限制shell(Restircted Shell)

sh -r 或 /bin/rsh

不能執行如下操作:cd, 更改PATH,指定全路徑名,輸出重定向,因此可以提供一個較

好的控制和安全機制。通常rsh用於應用型使用者及撥號使用者,這些使用者通常是看不到提

示符的。通常受限制使用者的主目錄是不可寫的。

不足:如果使用者可以呼叫sh,則rsh的限制將不在起作用,事實上如果使用者在vi及more

程式中呼叫shell,而這時rsh的限制將不再起作用。

(4)用set改變 shell選項

使用者可以在$提示符下用set命令來設定或取消shell的選項。使用-設定選項,+取消相應

選項,大多數UNIX系統允許a,e,f,h,k,n,u,v和x的開關設定/取消。

set -xv

啟動跟蹤方式;顯示所有的命令及替換,同樣顯示輸入。

set -tu

關閉在替換時對未定義變數的檢查。

使用echo $-顯示所有已設定的shell選項。

(5)使用者啟動檔案 .profile

PATH=$PATH:/usr/loacl/bin; export PATH

(6)shell環境變數

CDPATH 用於cd命令的查詢路徑

HOME /etc/passwd檔案中列出的使用者主目錄

IFS Internal Field Separator,預設為空格,tab及換行符

MAIL /var/mail/$USERNAME mail等程式使用

PATH

PS1,PS2 預設提示符($)及換行提示符(> )

TERM 終端型別,常用的有vt100,ansi,vt200,xterm等

示例:$PS1="test:";export PS1

test: PS1="$";export PS1

$echo $MAIL

/var/mail/username

(7)保留字元及其含義

$ shell變數名的開始,如$var

| 管道,將標準輸出轉到下一個命令的標準輸入

# 註釋開始

& 在後臺執行一個程式

? 匹配一個字元

* 匹配0到多個字元(與DOS不同,可在檔名中間使用,並且含.)

$- 使用set及執行時傳遞給shell的標誌位

$! 最後一個子程式的程式號

$# 傳遞給shell script的引數個數

$* 傳遞給shell script的引數

$@ 所有引數,個別的用雙引號括起來

$? 上一個命令的返回程式碼

$0 當前shell的名字

$n (n:1-) 位置引數

$$ 程式標識號(Process Identifier Number, PID)

>file 輸出重定向

`command` 命令替換,如 filename=`basename /usr/local/bin/tcsh`

>>fiile 輸出重定向,append

轉義符及單引號:

$echo "$HOME $PATH"

/home/hbwork /opt/kde/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:

$echo '$HOME $PATH'

$HOME $PATH

$echo $HOME $PATH

$HOME /opt/kde/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/hbwork/bin

其他:

$dir=ls

$$dir

$alias dir ls

$dir

ls > filelist

ls >> filelist

wc -l < filelist

wc -l filelist

sleep 5; echo 5 seconds reaches; ls -l

ps ax |egrep inetd

find / -name core -exec rm {} ; &

filename=`date "+%Y%m%d"`.log

2. shell變數

變數:代表某些值的符號,如$HOME,cd命令查詢$HOME,在計算機語言中可以使用變數可以

進行多種運算和控制。

Bourne Shell有如下四種變數:

.使用者自定義變數

.位置變數即 shell script之引數

.預定義變數(特殊變數)

.環境變數(參考shell定製部分)

(1)使用者自定義變數(資料的儲存)

$ COUNT=1

$ NAME="He Binwu"

技巧:因為大部分UNIX命令使用小寫字元,因此在shell程式設計中通常使用全大寫變數,

當然這並不是強制性的,但使用大寫字元可以在程式設計中方便地識別變數。

變數的呼叫:在變數前加$

$ echo $HOME

/home/hbwork

$ WEEK=Satur

$ echo Today is $WEEKday

Today is

$echo Today is ${WEEK}day

Today is Saturday

Shell變數賦值從右從左進行(Linux Shell/bash從左向右賦值!)

$ X=$Y Y=y

$ echo $X

y

$ Z=z Y=$Z

$ echo $Y

$

使用unset命令刪除變數的賦值

$ Z=hello

$ echo $Z

hello

$ unset Z

$ echo $Z

$

有條件的命令替換

在Bourne Shell中可以使變數替換在特定條件下執行,即有條件的環境變數替換。

這種變數替換總是用大括號括起來的。

.設定變數的預設值

在變數未賦值之前其值為空。Bourne Shell允許對變數設定預設值,其格式如下:

${variable:-defaultvalue}

例:

$ echo Hello $UNAME

Hello

$ echo Hello ${UNAME:-there}

Hello there

$ echo $UNAME #變數值並未發生變化

$ UNAME=hbwork

$ echo Hello ${UNAME:-there}

Hello hbwork

$

.另一種情況:改變變數的值,格式如下:

${variable:=value}

例:

$ echo Hello $UNAME

Hello

$ echo Hello ${UNAME:=there}

Hello there

$ echo $UNAME #變數值並未發生變化

there

$

.變數替換中使用命令替換

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

.在變數已賦值時進行替換 ${variable:+value}

.帶有錯誤檢查的有條件變數替換

${variable:?value}

例:

$ UNAME=

$ echo ${UNAME:?"UNAME has not been set"}

UNAME: UNAME has not been set

$ echo ${UNAME:?}

UNAME: parameter null or not set

(2)位置變數(Shell引數)

在shell script中位置引數可用$1..$9表示,$0表示內容通常為當前執行程式的檔名。

.防止變數值被替換 readonly variable

.使用export命令輸出變數,使得變數對子shell可用,當shell執行一下程式時,shell

將為其設定一個新的環境讓其執行,這稱之了subshell. 在Bourne Shell中變數通常

被認為是本地變數,也就是說在對其賦值之外的shell環境之外是不認識此變數的。使

用export對subshell可用。

例:對變數PS1的export操作,shell的提示符將發生變化。

$ PS1=`hostname`$

peony$sh

$ echo $PS1

$ $ exit

peony$export PS1

peony$sh

peony$ echo $PS1

peony$ peony$

3.Shell Script程式設計

目的:使用UNIX所提供的最常用工具來完成所需複雜任務的強大功能。

(1)最簡單的Shell 程式設計

$ls -R / |grep myname |more

每天資料的備份:

$ cd /usr/yourname; ls * |cpio -o > /dev/rmt/0h

書寫程式的目的是一次程式設計,多次使用(執行)!

$ cat > backup.sh

cd /home/hbwork

ls * | cpio -o > /dev/rmt/0h

^D

執行:

$ sh backup.sh

或:

$ chmod +x backup.sh

$ ./backup.sh

技巧:在shell script中加入必要的註釋,以便以後閱讀及維護。

(2)shell是一個(程式設計)語言

同傳統的程式語言一樣,shell提供了很多特性,這些特性可以使你的shell script

程式設計更為有用,如:資料變數、引數傳遞、判斷、流程控制、資料輸入和輸出,子

程式及以中斷處理等。

. 在shell程式設計中使用資料變數可以將程式變數更為通用,如在上面backup.sh中:

cd $WORKDIR

ls * | cpio -o > /dev/rmt/0h

. Shell程式設計中的註釋以#開頭

. 對shell變數進行數字運算,使用expr命令

expr integer operator integer

其中operator為+ - * / %, 但對*的使用要用轉義符,如:

$expr 4 * 5

20

$int=`expr 5 + 7`

$echo $int

12

(3)Shell程式設計的引數傳遞, 可透過命令列引數以及互動式輸入變數(read)

restoreall.sh 對backup.sh程式的備份磁帶進行恢復

$cat > restoreall.sh

cd $WORKDIR

cpio -i < /dev/rmt/0h

^D

restore1.sh:只能恢復一個檔案

#restore1 --program to restore a single file

cd $WORKDIR

cpio -i $i < /dev/rmt/0h

$restore1 file1

恢復多個檔案restoreany :

#restoreany --program to restore a single file

cd $WORKDIR

cpio -i $* < /dev/rmt/0h

$ restoreany file1 file2 file3

(4)條件判斷

. if-then語句,格式如下:

if command_1

then

command_2

command_3

fi

command_4

在if-then語句中使用了命令返回碼$?,即當command_1執行成功時才執行command_2和

command_3,而command_4總是執行.

示例程式unload: 在備份成功時刪除原始檔案,帶有錯誤檢查

cd $1

#備份時未考慮不成功的情況!

ls -a | cpio -o > /dev/rmt/0h

rm -rf *

改進如下:

#當使用了管道命令時,管理命令的返回程式碼為最後一個命令的返回程式碼

if ls -a | cpio -o > /dev/rmt/0h

then

rm -rf *

fi

. if-then-else語句

if command_1

then

command_2

else

command_3

fi

技巧: 由於shell對命令中的多餘的空格不作任何處理,一個好的程式設計師會用這一特性

對自己的程式採用統一的縮排格式,以增強自己程式的可讀性.

. 使用test命令進行進行條件測試

格式: test conditions

test在以下四種情況下使用: a. 字元比較 b.兩個整數值的比較

c. 檔案操作,如檔案是否存在及檔案的狀態等

d. 邏輯操作,可以進行and/or,與其他條件聯合使用

a. 測試字元資料: shell變數通常民政部下均作為字元變數

str1 = str2 二者相長,相同

str1 != str2 不同

-n string string不為空(長度不為零)

-z string string為空

string string不為空

例:

$ str1=abcd #在含有空格時必須用引號括起來

$ test $str1=abcd

$ echo $?

0

$ str1="abcd "

$ test $str1=abcd

$ echo $?

1

Note: 在test處理含有空格的變數時最好用引號將變數括起來,否則會出現錯誤的結果,

因為shell在處理命令列時將會去掉多餘的空格,而用引號括起來則可以防止

shell去掉這些空格.

例:

$ str1=" "

$ test $str1

$ echo $?

1

$ test "$str1"

$ echo $?

0

$ test -n $str1

test: argument expected

$ test -n "$str1"

$ echo $?

0

$

b. 整數測試: test與expr相同,可以將字元型變數轉換為整數進行操作,expr進行

整數的算術運算,而test則進行邏輯運算.

表示式 說明

---------------------------------------

int1 -eq int2 相等?

int1 -ne int2 不等?

int1 -gt int2 int1 > int2 ?

int1 -ge int2 int1 >= int2 ?

int1 -lt int2 int1 < int2 ?

int1 -le int2 int1 <= int2 ?

例:

$ int1=1234

$ int2=01234

$ test $int1 -eq $int2

$ echo $?

0

c. 檔案測試:檢查檔案狀態如存在及讀寫許可權等

-r filename 使用者對檔案filename有讀許可權?

-w filename 使用者對檔案filename有寫許可權?

-x filename 使用者對檔案filename有可執行許可權?

-f filename 檔案filename為普通檔案?

-d filename 檔案filename為目錄?

-c filename 檔案filename為字元裝置檔案?

-b filename 檔案filename為塊裝置檔案?

-s filename 檔案filename大小不為零?

-t fnumb 與檔案描述符fnumb(預設值為1)相關的裝置是一個終端裝置?

d. 測試條件之否定,使用!

例:

$ cat /dev/null > empty

$ test -r empty

$ echo $?

0

$ test -s empty

1

$ test ! -s empty

$ echo $?

0

e. 測試條件之邏輯運算

-a And

-o Or

例: $ test -r empty -a -s empty

$ echo $?

1

f. 進行test測試的標準方法

因為test命令在 shell程式設計中佔有很重要的地位,為了使shell能同其他程式語言一樣

便於閱讀和組織, Bourne Shell在使用test測試時使用了另一種方法:用方括號將整個

test測試括起來:

$ int1=4

$ [ $int1 -gt 2 ]

$ echo $?

0

例: 重寫unload程式,使用test測試

#!/bin/sh

#unload - program to backup and remove files

#syntax: unload directory

#check arguments

if [ $# -ne 1 ]

then

echo "usage: $0 directory"

exit 1

fi

#check for valid directory name

if [ ! -d "$1" ]

then

echo "$1 is not a directory"

exit 2

fi

cd $1

ls -a | cpio -o > /dev/rmt/0h

if [ $? -eq 0 ]

then

rm -rf *

else

echo "A problem has occured in creating backup"

echo "The directory will not be ereased"

echo "Please check the backup device"

exit 3

fi

# end of unload

在如上示例中出現了exit, exit有兩個作用:一是停止程式中其他命令的執行,二是

設定程式的退出狀態

g. if巢狀及elif結構

if command

then

command

else

if command

then

command

else

if command

then

command

fi

fi

fi

改進:使用elif結構

if command

then

command

elif command

then

command

elif command

then

command

fi

elif結構同if結構類似,但結構更清淅,其執行結果完全相同.

h.互動式從鍵盤讀入資料

使用read語句,其格式如下:

read var1 var2 ... varn

read將不作變數替換,但會刪除多餘的空格,直到遇到第一個換行符(回車),

並將輸入值依次賦值給相應的變數。

例:

$ read var1 var2 var3

Hello my friends

$ echo $var1 $var2 $var3

Hello my friends

$ echo $var1

Hello

$ read var1 var2 var3

Hello my dear friends

$ echo $var3

dear friends $ read var1 var2 var3

Hello friends

$ echo $var3

$

在shell script中可使用read語句進行互動操作:

...

#echo -n message 輸出結果後不換行

echo -n "Do you want to continue: Y or N"

read ANSWER

if [ $ANSWER=N -o $ANSWER=n ]

then

exit

fi

i. case結構:結構較elif-then結構更清楚

比較if-then語句:

if [ variable1 = value1 ]

then

command

command

elif [ variable1 = value2 ]

then

command

command

elif [ variable1 = value3 ]

then

command

command

fi

相應的case結構:

case value in

pattern1)

command

command;;

pattern2)

command

command;;

...

patternn)

command;

esac

* case語句只執行第一個匹配模式

例:使用case語句建立一個選單選擇shell script

#Display a menu

echo _

echo "1 Restore"

echo "2 Backup"

echo "3 Unload"

echo

#Read and excute the user's selection

echo -n "Enter Choice:"

read CHOICE

case "$CHOICE" in

1) echo "Restore";;

2) echo "Backup";;

3) echo "Unload";;

*) echo "Sorry $CHOICE is not a valid choice

exit 1

esac

在上例中,*指預設匹配動作。此外,case模式中也可以使用邏輯操作,如下所示:

pattern1 | pattern2 ) command

command ;;

這樣可以將上面示例程式中允許使用者輸入數字或每一個大寫字母。

case "$CHOICE" in

1|R) echo "Restore";;

2|B) echo "Backup";;

3|U) echo "Unload";;

*) echo "Sorry $CHOICE is not a valid choice

exit 1

esac

(5)迴圈控制

<1> while迴圈:

格式:

while command

do

command

command

command

...

done

例: 計算1到5的平方

#!/bin/sh

#

#Filename: square.sh

int=1

while [ $int -le 5 ]

do

sq=`expr $int * $int`

echo $sq

int=`expr $int + 1`

done

echo "Job completed"

$ sh square.sh

1

4

9

16

25

Job completed

<2> until迴圈結構:

格式:

until command

do

command

command

....

command

done

示例:使用until結構計算1-5的平方

#!/bin/sh

int=1

until [ $int -gt 5 ]

do

sq=`expr $int * $int`

echo $sq

int=`expr $int + 1`

done

echo "Job completed"

<3> 使用shift對不定長的引數進行處理

在以上的示例中我們總是假設命令列引數唯一或其個數固定,或者使用$*將整個命令

行引數傳遞給shell script進行處理。對於引數個數不固定並且希望對每個命令引數

進行單獨處理時則需要shift命令。使用shift可以將命令列位置引數依次移動位置,

即$2->$1, $3->$2. 在移位之前的第一個位置引數$1在移位後將不在存在。

示例如下:

#!/bin/sh

#

#Filename: shifter

until [ $# -eq 0 ]

do

echo "Argument is $1 and `expr $# - 1` argument(s) remain"

shift

done

$ shifter 1 2 3 4

Argument is 1 and 3 argument(s) remain

Argument is 2 and 2 argument(s) remain

Argument is 3 and 1 argument(s) remain

Argument is 4 and 0 argument(s) remain

$

使用shift時,每進行一次移位,$#減1,使用這一特性可以用until迴圈對每個參

數進行處理,如下示例中是一個求整數和的shell script:

#!/bin/sh

# sumints - a program to sum a series of integers

#

if [ $# -eq 0 ]

then

echo "Usage: sumints integer list"

exit 1

fi

sum=0

until [ $# -eq 0 ]

do

sum=`expr $sum + $1`

shift

done

echo $sum

$ sh sumints 324 34 34 12 34

438

$

使用shift的另一個原因是Bourne Shell的位置引數變數為$1~$9, 因此透過位置變數

只能訪問前9個引數。但這並不等於在命令列上最多隻能輸入9個引數。此時如果想訪問

前9個引數之後的引數,就必須使用shift.

另外shift後可加整數進行一次多個移位,如:

shift 3

<4>. for迴圈

格式:

for var in arg1 arg2 ... argn

do

command

....

command

done

示例:

$ for letter in a b c d e; do echo $letter;done

a

b

c

d

e

對當前目錄下的所有檔案操作:

$ for i in *

do

if [ -f $i ]

then

echo "$i is a file"

elif [ -d $i ]

echo "$i is a directory"

fi

done

求命令列上所有整數之和:

#!/bin/sh

sum=0

for INT in $*

do

sum=`expr $sum + $INT`

done

echo $sum

<6> 從迴圈中退出: break和continue命令

break 立即退出迴圈

continue 忽略本迴圈中的其他命令,繼續下一下迴圈

在shell程式設計中有時我們要用到進行無限迴圈的技巧,也就是說這種迴圈一直執行碰

到break或continue命令。這種無限迴圈通常是使用true或false命令開始的。UNIX

系統中的true總是返加0值,而false則返回非零值。如下所示:

#一直執行到程式執行了break或使用者強行中斷時才結束迴圈

while true

do

command

....

command

done

上面所示的迴圈也可以使用until false, 如下:

until false

do

command

....

command

done

在如下shell script中同時使用了continue,break以及case語句中的正規表示式用法:

#!/bin/sh

# Interactive program to restore, backup, or unload

# a directory

echo "Welcome to the menu driven Archive program"

while true

do

# Display a Menu

echo

echo "Make a Choice from the Menu below"

echo _

echo "1 Restore Archive"

echo "2 Backup directory"

echo "3 Unload directory"

echo "4 Quit"

echo

# Read the user's selection

echo -n "Enter Choice: "

read CHOICE

case $CHOICE in

[1-3] ) echo

# Read and validate the name of the directory

echo -n "What directory do you want? "

read WORKDIR

if [ ! -d "$WORKDIR" ]

then

echo "Sorry, $WORKDIR is not a directory"

continue

fi

# Make the directory the current working directory

cd $WORKDIR;;

4) :;; # :為空語句,不執行任何動作

*) echo "Sorry, $CHOICE is not a valid choice"

continue

esac

case "$CHOICE" in

1) echo "Restoring..."

cpio -i

2) echo "Archiving..."

ls | cpio -o >/dev/rmt/0h;;

3) echo "Unloading..."

ls | cpio -o >/dev/rmt/0h;;

4) echo "Quitting"

break;;

esac

#Check for cpio errors

if [ $? -ne 0 ]

then

echo "A problem has occurred during the process"

if [ $CHOICE = 3 ]

then

echo "The directory will not be erased"

fi

echo "Please check the device and try again"

continue

else

if [ $CHOICE = 3 ]

then

rm *

fi

fi

done

(6)結構化程式設計:定義函式

同其他高階語言一樣,shell也提供了函式功能。函式通常也稱之為子過程(subroutine),

其定義格式如下:

funcname()

{

command

...

command; #分號

}

定義函式之後,可以在shell中對此函式進行呼叫,使用函式定義可以將一個複雜的程式分

為多個可管理的程式段,如下所示:

# start program

setup ()

{ command list ; }

do_data ()

{ command list ; }

cleanup ()

{ command list ; }

errors ()

{ command list ; }

setup

do_data

cleanup

# end program

技巧:

. 在對函式命名時最好能使用有含義的名字,即函式名能夠比較準確的描述函式所完成

的任務。

. 為了程式的維護方便,請儘可能使用註釋

使用函式的另一個好處就是可以在一個程式中的不同地方執行相同的命令序列(函式),

如下所示:

iscontinue()

{

while true

do

echo -n "Continue?(Y/N)"

read ANSWER

case $ANSWER in

[Yy]) return 0;;

[Nn]) return 1;;

*) echo "Answer Y or N";;

esac

done

}

這樣可以在shell程式設計中呼叫iscontinue確定是否繼續執行:

if iscontinue

then

continue

else

break

fi

** shell函式與shell程式非常相似,但二者有一個非常重要的差別:shell程式是由子shell

執行的,而shell函式則是作為當前shell的一部分被執行的,因此在當前shell中可以改

變函式的定義。此外在任意shell(包括互動式的shell)中均可定義函式,如:

$ dir

dir: not found

$ dir () { ls -l ;}

$ dir

total 5875

-rw-r--r-- 1 hbwork 100 Nov 10 23:16 doc

-rw-r--r-- 1 hbwork 2973806 Nov 10 23:47 ns40docs.zip

-rw-r--r-- 1 hbwork 1715011 Nov 10 23:30 ns840usr.pdf

-rw-r--r-- 1 hbwork 1273409 Sep 23 1998 radsol21b6.tar.Z

-rw-r--r-- 1 hbwork 7526 Nov 10 23:47 wget-log

-rw-r--r-- 1 hbwork 1748 Nov 13 21:51 wget-log.1

$ unset dir

$ dir () {

> echo "Permission Link Owner Group File_SZ LastAccess FileName"

> echo "-----------------------------------------------------------"

> ls -l $*;

> }

$ dir

Permission Link Owner Group File_SZ LastAccess FileName

-----------------------------------------------------------

total 5875

-rw-r--r-- 1 hbwork 100 Nov 10 23:16 doc

-rw-r--r-- 1 hbwork 2973806 Nov 10 23:47 ns40docs.zip

-rw-r--r-- 1 hbwork 1715011 Nov 10 23:30 ns840usr.pdf

-rw-r--r-- 1 hbwork 1273409 Sep 23 1998 radsol21b6.tar.Z

-rw-r--r-- 1 hbwork 7526 Nov 10 23:47 wget-log

-rw-r--r-- 1 hbwork 1748 Nov 13 21:51 wget-log.1

通常情況下,shell script是在子shell中執行的,困此在此子shell中對變數所作的

修改對父shell不起作用。點(.) 命令使用shell在不建立子shell而由當前shell讀取

並執行一個shell script, 可以透過這種方式來定義函式及變數。此外點(.)命令最

常用的功能就是透過讀取.profile來重新配置初始化login變數。如下所示:

$ . .profile

(csh相對於.命令的是source命令).

(7)使用And/Or結構進行有條件的命令執行

<1> And , 僅當第一個命令成功時才有執行後一個命令,如同在邏輯與表示式中如果前面的

結果為真時才有必要繼續運算,否則結果肯定為假。

格式如下:

command1 && command2

例:rm $TEMPDIR/* && echo "File successfully removed"

等價於

if rm $TEMPDIR/*

then

echo "File successfully removed"

fi

<2>Or, 與AND相反,僅當前一個命令執行出錯時才執行後一條命令

例: rm $TEMPDIR/* || echo "File not removed"

等價與:

if rm $TEMPDIR/*

then

command

else

echo "File not removed"

fi

<3> 混合命令條件執行

command1 && command2 && command3

當command1, command2成功時才執行command3

command1 && command2 || comamnd3

僅當command1成功,command2失敗時才執行command3

當然可以根據自己的需要進行多種條件命令的組合,在此不多講述。

(8) 使用getopts命令讀取unix格式選項

UNIX格式選項指如下格式的命令列引數:

command -options parameters

使用格式:

getopts option_string variable

具體使用方法請參考getopts的線上文件(man getopts).

示例如下:

#newdate

if [ $# -lt 1 ]

then

date

else

while getopts mdyDHMSTjJwahr OPTION

do

case $OPTION

in

m) date '+%m ';; # Month of Year

d) date '+%d ';; # Day of Month

y) date '+%y ';; # Year

D) date '+%D ';; # MM/DD/YY

H) date '+%H ';; # Hour

M) date '+%M ';; # Minute

S) date '+%S ';; # Second

T) date '+%T ';; # HH:MM:SS

j) date '+%j ';; # day of year

J) date '+%y%j ';;# 5 digit Julian date

w) date '+%w ';; # Day of the Week

a) date '+%a ';; # Day abbreviation

h) date '+%h ';; # Month abbreviation

r) date '+%r ';; # AM-PM time

?) echo "Invalid option $OPTION";;

esac

done

fi

$ newdate -J

94031

$ newdate -a -h -d

Mon

Jan

31

$ newdate -ahd

Mon

Jan

31

$

示例程式:複製程式

# Syntax: duplicate [-c integer] [-v] filename

# where integer is the number of duplicate copies

# and -v is the verbose option

COPIES=1

VERBOSE=N

while getopts vc: OPTION

do

case $OPTION

in

c) COPIES=$OPTARG;;

v) VERBOSE=Y;;

?) echo "Illegal Option"

exit 1;;

esac

done

if [ $OPTIND -gt $# ]

then

echo "No file name specified"

exit 2

fi

shift `expr $OPTIND -1`

FILE=$1

COPY=0

while [ $COPIES -gt $COPY ]

do

COPY=`expr $COPY + 1`

cp $FILE ${FILE}${COPY}

if [ VERBOSE = Y ]

then

echo ${FILE}${COPY}

fi

done

$ duplicate -v fileA

fileA1

$ duplicate -c 3 -v fileB

fileB1

fileB2

fileB3

4. Shell的定製

通常使用shell的定製來控制使用者自己的環境,比如改變shell的外觀(提示符)以及增強

自己的命令。

(1)通常環境變數來定製shell

通常改變環境變數可以定製shell的工作環境。shell在處理資訊時會參考這些環境變數

,改變環境變數的值在一定程度上改變shell的操作方式,比如改變命令列提示符。

.使用IFS增加命令列分隔符

預設狀態下shell的分隔符為空格、製表符及換行符,但可以透過改變IFS的值加入自己

的分隔符。如下所示:

$ IFS=":"

$ echo:Hello:my:Friend

Hello my Friend

(2)加入自己的命令及函式

如下程式:

#Directory and Prompt change program

#Syntax: chdir directory

if [ ! -d "$1" ]

then

echo "$1 is not a directory"

exit 1

fi

cd $1

PS1=`pwd`$

export PS1

$ chdir /usr/home/teresa

$

但此程式在執行時系統提示符並不會改變,因為此程式是在子shell中執行的。因此其變數

對當前shell並無影響,要想對當前shell起作用,最好是將此作為函式寫在自己的.profile中

或建立自己的個人函式檔案.persfuncs

#Personal function file persfuncs

chdir()

{

#Directory and Prompt change program

#Syntax: chdir directory

if [ ! -d "$1" ]

then

echo "$1 is not a directory"

exit 1

fi

cd $1

PS1=`pwd`$

export PS1;

}

再執行:

$ . .persfuncs

$ chdir temp

/home/hbbwork/temp$

也可在自己的.profile檔案中用 . .persfuncs呼叫.persfuncs.

說明:在bash/tcsh中已經使用別名,相對而言別名比此方法更為方便。

5. 有關shell的專門討論

(1)shell程式的除錯

切記:程式設計師(人)總是會犯錯誤的,而計算機是不會錯的。

使用-x進行跟蹤執行,執行並顯示每一條指令。

(2)命令組

用小括號將一組命令括起來,則這些命令會由子shell來完成;而{command_list;}則在當

前shell中執行。這兩者的主要區別在於其對shell變數的影響,子shell執行的命令不會

影響當前shell中的變數。

$ NUMBER=2

$ (A=2;B=2;NUMBER=`expr $A + $B`; echo $NUMBER)

4

$ echo $NUMBER

2

$ { A=2;B=2;NUMBER=`expr $A + $B`; echo $NUMBER; }

4

$ echo $NUMBER

4

總結:

在本章中講述了Bourne Shell的基本知識,使用shell變數,shell script基礎。這些概念

對於理解學習Korn Shell, csh以及其他script程式設計都是非常有用的。

很多OS都有不少語言及一些script功能,但很少有象UNIX SHELL這樣靈活強大的script腳

本語言能力。

對於系統管理員或程式設計師來說,熟練地使用shell script將對日常工作(系統維護及管理)

非常有用,如果你想作一個合格的系統管理員,強烈建議你進一步深入的瞭解和使用

shell.

另外,對於系統管理員來說,PERL也是一個必不可少的script程式語言,尤其是對於處理

文字格式的各種檔案,PERL具有shell, awk, sed, grep等的功能,但使用起來更為靈活,

功能也更強大。大家可以參考“Perl By Examples"來學習和使用PERL。

made by pageshop of CERNET network centre of DaLian region.copyright 199

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-944881/,如需轉載,請註明出處,否則將追究法律責任。

相關文章