歡迎您光臨本站 註冊首頁

bash 經典 <收藏>

←手機掃碼閱讀     火星人 @ 2014-03-24 , reply:0

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/hbw
ork/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結構類似,但結構更清淅,其執行結果完全相同

Bourne Shell及Shell編程(2)
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
<- 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程序是由子sh
ell
執行的,而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

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


( 使用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。


創建腳本
功能測試是軟體開發的一個關鍵部分 -- 而已經裝入 Linux 的 Bash 可以幫您輕而易舉地完成功能測試。在本文中,Angel Rivera 將說明如何運用 Bash shell 腳本通過行命令來執行 Linux 應用程序的功能測試。由於此腳本依賴於命令行的返回碼,因而您不能將這種方法運用於 GUI 應用程序。

功能測試是開發周期的一個階段,在這個階段中將測試軟體應用程序以確保軟體的函數如預期的那樣,同時能正確處理代碼中錯誤。此項工作通常在單個模塊的單元測試結束之後,在負載/重壓條件下整個產品的系統測試之前進行的。

市場上有許多測試工具提供了有助於功能測試的功能。然而,首先要獲取它們,然後再安裝、配置,這將佔用您寶貴的時間和精力。Bash 可以幫您免去這些煩瑣的事從而可以加快測試的進程。

使用 Bash shell 腳本進行功能測試的優點在於:
Bash shell 腳本已經在 Linux 系統中安裝和配置好了。不必再花時間準備它。
可以使用由 Linux 提供的文本編輯器如 vi 創建和修改 Bash shell 腳本。不需要再為創建測試程序而獲取專門的工具。
如果已經知道了如何開發 Bourne 或 Korn shell 腳本,那對於如何運用 Bash shell 腳本已經足夠了。對您來說,學習曲線已不存在了。
Bash shell 提供了大量的編程構造用於開發從非常簡單到中等複雜的腳本。

將腳本從 Korn 移植到 Bash 時的建議
如果已有現成的 Korn shell 腳本,而想要將它們移植到 Bash,就需要考慮下列情況:

Korn 的 "print" 命令在 Bash 中不能使用;而是改為使用 "echo" 命令。
需要將腳本的第一行:
#!/usr/bin/ksh
修改成:
#!/bin/bash

創建 Bash shell 腳本進行功能測試
這些基本的步驟和建議適用於許多在 Linux 上運行的客戶機/伺服器應用程序。

記錄運行腳本的先決條件和主要步驟
將操作分成若干個邏輯組
基於一般方案制定執行步驟
在每個 shell 腳本中提供註釋和說明
做一個初始備份以創建基準線
檢查輸入參數和環境變數
嘗試提供 "usuage" 反饋
嘗試提供一個"安靜"的運行模式
當出現錯誤時,提供一個函數終止腳本
如可能,提供可以執行單個任務的函數
當顯示正在生成的輸出時,捕獲每個腳本的輸出
在每個腳本內,捕獲每個行命令的返回碼
計算失敗事務的次數
在輸出文件中,突出顯示錯誤消息,以便於標識
如有可能,"實時"生成文件
在執行腳本的過程中提供反饋
提供腳本執行的摘要
提供一個容易解釋的輸出文件
如有可能,提供清除腳本及返回基準線的方法



下面詳細講述了每一條建議以及用於說明問題的腳本。若要下載此腳本,請參閱本文後面的參考資料部分。


1. 記錄運行腳本的先決條件和主要步驟
記錄,尤其是以有自述標題的單個文件(例如 "README-testing.txt")記錄功能測試的主要想法是很重要的,包括,如先決條件、伺服器和客戶機的設置、腳本遵循的整個(或詳細的)步驟、如何檢查腳本的成功/失敗、如何執行清除和重新啟動測試。


2. 將操作分成若干個邏輯組
如果僅僅執行數量非常少的操作,可以將它們全部放在一個簡單的 shell 腳本中。


但是,如果需要執行一些數量很多的操作,那最好是將它們分成若干個邏輯集合,例如將一些伺服器操作放在一個文件而將客戶機操作放在在另一個文件中。通過這種方法,劃分適當的顆粒度來執行測試和維護測試。


3. 基於一般方案制定執行步驟
一旦決定對操作進行分組,需要根據一般方案考慮執行操作的步驟。此想法是模擬實際生活中最終用戶的情形。作為一個總體原則,只需集中測試 80% 最常調用函數的 20% 用法即可。


例如,假設應用程序要求 3 個測試組以某個特定的順序排列。每個測試組可以放在一個帶有自我描述文件名(如果可能)的文件中,並用號碼來幫助識別每個文件的順序,例如:



源碼:--------------------------------------------------------------------------------1. fvt-setup-1: To perform initial setup.
2. fvt-server-2: To perform server commands.
3. fvt-client-3: To perform client commands.
4. fvt-cleanup: To cleanup the temporary files,
in order to prepare for the repetition
of the above test cases.
--------------------------------------------------------------------------------

4. 在每個 shell 腳本中提供註釋和說明
在每個 shell 腳本的頭文件中提供相關的註釋和說明是一個良好的編碼習慣。這樣的話,當另一個測試者運行該腳本時,測試者就能清楚地了解每個腳本中測試的範圍、所有先決條件和警告。


下面是一個 Bash 腳本 "test-bucket-1" 的示例 。



源碼:--------------------------------------------------------------------------------#!/bin/bash
#
# Name: test-bucket-1
#
# Purpose:
# Performs the test-bucket number 1 for Product X.
# (Actually, this is a sample shell script,
# which invokes some system commands
# to illustrate how to construct a Bash script)
#
# Notes:
# 1) The environment variable TEST_VAR must be set
# (as an example).
# 2) To invoke this shell script and redirect standard
# output and standard error to a file (such as
# test-bucket-1.out) do the following (the -s flag
# is "silent mode" to avoid prompts to the user):
#
# ./test-bucket-1 -s 2>&1 | tee test-bucket-1.out
#
# Return codes:
# 0 = All commands were successful
# 1 = At least one command failed, see the output file
# and search for the keyword "ERROR".
#
########################################################
--------------------------------------------------------------------------------

5. 做一個初始備份以創建基準線
您可能需要多次執行功能測試。第一次運行它時,也許會找到腳本或進程中的一些錯誤。因而,為了避免因從頭重新創建伺服器環境而浪費大量時間 -- 特別是如果涉及到資料庫 -- 您在測試之前或許想做個備份。


在運行完功能測試之後,就可以從備份中恢復伺服器了,同時也為下一輪測試做好了準備。


6. 檢查輸入參數和環境變數
最好校驗一下輸入參數,並檢查環境變數是否設置正確。如果有問題,顯示問題的原因及其修復方法,然後終止腳本。


當測試者準備運行腳本,而此時如果沒有正確設置腳本所調用的環境變數,但由於發現及時,終止了腳本,那測試者會相當感謝。沒有人喜歡等待腳本執行了很久卻發現沒有正確設置變數。

源碼:--------------------------------------------------------------------------------
# --------------------------------------------
# Main routine for performing the test bucket
# --------------------------------------------

CALLER=`basename $0` # The Caller name
SILENT="no" # User wants prompts
let "errorCounter = 0"

# ----------------------------------
# Handle keyword parameters (flags).
# ----------------------------------

# For more sophisticated usage of getopt in Linux,
# see the samples file: /usr/lib/getopt/parse.bash

TEMP=`getopt hs $*`
if [ $? != 0 ]
then
echo "$CALLER: Unknown flag(s)"
usage
fi

# Note quotes around `$TEMP': they are essential!
eval set -- "$TEMP"

while true
do
case "$1" in
-h) usage "HELP"; shift;; # Help requested
-s) SILENT="yes"; shift;; # Prompt not needed
--) shift ; break ;;
*) echo "Internal error!" ; exit 1 ;;
esac
done

# ------------------------------------------------
# The following environment variables must be set
# ------------------------------------------------

if [ -z "$TEST_VAR" ]
then
echo "Environment variable TEST_VAR is not set."
usage
fi
--------------------------------------------------------------------------------

關於此腳本的說明如下:

使用語句 CALLER=`basename $0` 可以得到正在運行的腳本名稱。這樣的話,無須在腳本中硬編碼腳本名稱。因此當複製腳本時,採用新派生的腳本可以減少工作量。
調用腳本時,語句 TEMP=`getopt hs $*` 用於得到輸入變數(例如 -h 代表幫助,-s 代表安靜模式)。
語句 [ -z "$X" ] 和 echo "The environment variable X is not set." 以及 usage 都是用於檢測字元串是否為空 (-z),如果為空,隨後就執行 echo 語句以顯示未設置字元串並調用下面要討論的 "usage" 函數。
若腳本未使用標誌,可以使用變數 "$#",它可以返回正在傳遞到腳本的變數數量。

7. 嘗試提供"usage"反饋
腳本中使用 "usage" 語句是個好主意,它用來說明如何使用腳本。

源碼:--------------------------------------------------------------------------------
# ----------------------------
# Subroutine to echo the usage
# ----------------------------

usage()
{
echo "USAGE: $CALLER [-h] [-s]"
echo "WHERE: -h = help "
echo " -s = silent (no prompts)"
echo "PREREQUISITES:"
echo "* The environment variable TEST_VAR must be set,"
echo "* such as: "
echo " export TEST_VAR=1"
echo "$CALLER: exiting now with rc=1."
exit 1
}
--------------------------------------------------------------------------------

調用腳本時,使用"-h"標誌可以調用 "usage" 語句,如下所示:
./test-bucket-1 -h


8. 嘗試使用"安靜"的運行模式
您或許想讓腳本有兩種運行模式:

在 "verbose" 模式(您也許想將此作為預設值)中提示用戶輸入值,或者只需按下 Enter 繼續運行。
在 "silent" 模式中將不提示用戶輸入數據。

下列摘錄說明了在安靜模式下運用所調用標誌 "-s" 來運行腳本:

源碼:--------------------------------------------------------------------------------
# -------------------------------------------------
# Everything seems OK, prompt for confirmation
# -------------------------------------------------

if [ "$SILENT" = "yes" ]
then
RESPONSE="y"
else
echo "The $CALLER will be performed."
echo "Do you wish to proceed [y or n]? "
read RESPONSE # Wait for response
[ -z "$RESPONSE" ] && RESPONSE="n"
fi

case "$RESPONSE" in
[yY]|[yY][eE]|[yY][eE][sS])
;;
*)
echo "$CALLER terminated with rc=1."
exit 1
;;
esac
--------------------------------------------------------------------------------


9. 當出現錯誤時,提供一個函數終止腳本
遇到嚴重錯誤時,提供一個中心函數以終止運行的腳本不失為一個好主意。此函數還可提供附加的說明,用於指導在此情況下應做些什麼:


源碼:--------------------------------------------------------------------------------

# ----------------------------------
# Subroutine to terminate abnormally
# ----------------------------------

terminate()
{
echo "The execution of $CALLER was not successful."
echo "$CALLER terminated, exiting now with rc=1."
dateTest=`date`
echo "End of testing at: $dateTest"
echo ""
exit 1
}
--------------------------------------------------------------------------------

10. 如有可能,提供可以執行簡單任務的函數
例如,不使用許多很長的行命令,如:

源碼:--------------------------------------------------------------------------------
# --------------------------------------------------
echo ""
echo "Creating Access lists..."
# --------------------------------------------------

Access -create -component Development -login ted -authority plead -verbose
if [ $? -ne 0 ]
then
echo "ERROR found in Access -create -component Development -login ted
-authority plead"
let "errorCounter = errorCounter + 1"
fi

Access -create -component Development -login pat -authority general -verbose
if [ $? -ne 0 ]
then
echo "ERROR found in Access -create -component Development -login pat
-authority general"
let "errorCounter = errorCounter + 1"
fi

Access -create -component Development -login jim -authority general -verbose
if [ $? -ne 0 ]
then
echo "ERROR found in Access -create -component Development -login jim
-authority general"
let "errorCounter = errorCounter + 1"
fi
--------------------------------------------------------------------------------

……而是創建一個如下所示的函數,此函數也可以處理返回碼,如果有必要,還可以增加錯誤計數器:

源碼:--------------------------------------------------------------------------------
CreateAccess()
{
Access -create -component $1 -login $2 -authority $3 -verbose
if [ $? -ne 0 ]
then
echo "ERROR found in Access -create -component $1 -login $2 -authority $3"
let "errorCounter = errorCounter + 1"
fi
}
--------------------------------------------------------------------------------

……然後,以易讀和易擴展的方式調用此函數:

源碼:--------------------------------------------------------------------------------
# -------------------------------------------
echo ""
echo "Creating Access lists..."
# -------------------------------------------

CreateAccess Development ted projectlead
CreateAccess Development pat general
CreateAccess Development jim general

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

11. 當顯示正在生成的輸出時,捕獲每個腳本的輸出
如果腳本不能自動地將輸出發送到文件的話,可以利用 Bash shell 的一些函數來捕獲所執行腳本的輸出,如:

./test-bucket-1 -s 2>&1 | tee test-bucket-1.out

讓我們來分析上面的命令:

"2>&1" 命令:

使用 "2>&1" 將標準錯誤重定向到標準輸出。字元串 "2>&1" 表明任何錯誤都應送到標準輸出,即 UNIX/Linux 下 2 的文件標識代表標準錯誤,而 1 的文件標識代表標準輸出。如果不用此字元串,那麼所捕捉到的僅僅是正確的信息,錯誤信息會被忽略。

管道 "|" 和 "tee" 命令:

UNIX/Linux 進程和簡單的管道概念很相似。既然這樣,可以做一個管道將期望腳本的輸出作為管道的輸入。下一個要決定的是如何處理管道所輸出的內容。在這種情況下,我們會將它捕獲到輸出文件中,在此示例中將之稱為 "test-bucket-1.out"。


但是,除了要捕獲到輸出結果外,我們還想監視腳本運行時產生的輸出。為達到此目的,我們連接允許兩件事同時進行的 "tee" (T- 形管道):將輸出結果放在文件中同時將輸出結果顯示在屏幕上。 其管道類似於:


源碼:--------------------------------------------------------------------------------
process --> T ---> output file
|
V
screen
--------------------------------------------------------------------------------


如果只想捕獲輸出結果而不想在屏幕上看到輸出結果,那可以忽略多餘的管道: ./test-bucket-1 -s 2>&1 > test-bucket-1.out


假若這樣,相類似的管道如下:

process --> output file

12. 在每個腳本內,捕獲每個行命令所返回碼
決定功能測試成功還是失敗的一種方法是計算已失敗行命令的數量,即返回碼不是 0。變數 "$?" 提供最近所調用命令的返回碼;在下面的示例中,它提供了執行 "ls" 命令的返回碼。

源碼:--------------------------------------------------------------------------------
# -------------------------------------------
# The commands are called in a subroutine
# so that return code can be
# checked for possible errors.
# -------------------------------------------
ListFile()
{
echo "ls -al $1"
ls -al $1
if [ $? -ne 0 ]
then
echo "ERROR found in: ls -al $1"
let "errorCounter = errorCounter + 1"
fi
}
--------------------------------------------------------------------------------

13. 記錄失敗事務的次數
在功能測試中決定其成功或失敗的一個方法是計算返回值不是 0 的行命令數量。但是,從我個人的經驗而言,我習慣於在我的 Bash shell 腳本中僅使用字元串而不是整數。在我所參考的手冊中沒有清楚地說明如何使用整數,這就是我為什麼想在此就關於如何使用整數和計算錯誤(行命令失敗)數量的方面多展開講的原因:
首先,需要按如下方式對計數器變數進行初始化:

let "errorCounter = 0"

然後,發出行命令並使用 $? 變數捕獲返回碼。如果返回碼不是 0,那麼計數器增加 1(見藍色粗體語句):

源碼:--------------------------------------------------------------------------------
ListFile()
{
echo "ls -al $1"
ls -al $1
if [ $? -ne 0 ]
then
echo "ERROR found in: ls -al $1"
let "errorCounter = errorCounter + 1"
fi
}
--------------------------------------------------------------------------------


順便說一下,與其它變數一樣,可以使用 "echo" 顯示整數變數。


14. 在輸出文件中,為了容易標識,突出顯示錯誤消息
當遇到錯誤(或失敗的事務)時,除了錯誤計數器的數量會增加外,最好標識出此處有錯。較理想的做法是,字元串有一個如 ERROR 或與之相似的子串(見藍色粗體的語句),這個子串允許測試者很快地在輸出文件中查找到錯誤。此輸出文件可能很大,而且它對於迅速找到錯誤非常重要。



源碼:--------------------------------------------------------------------------------
ListFile()
{
echo "ls -al $1"
ls -al $1
if [ $? -ne 0 ]
then
echo "ERROR found in: ls -al $1"
let "errorCounter = errorCounter + 1"
fi
}
--------------------------------------------------------------------------------


15. 如有可能,"實時"生成文件
在某些情況下,有必要處理應用程序使用的文件。可以使用現有文件,也可以在腳本中添加語句來創建文件。如果要使用的文件很長,那最好將其作為獨立的實體。如果文件很小而且內容簡單或不相關(重要的一點是文本文件而不考慮它的內容),那就可以決定"實時"創建這些臨時文件。


下面幾行代碼顯示如何"實時"創建臨時文件:

源碼:--------------------------------------------------------------------------------
cd $HOME/fvt

echo "Creating file softtar.c"

echo "Subject: This is softtar.c" > softtar.c
echo "This is line 2 of the file" >> softtar.c

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

第一個 echo 語句使用單個的 > 強行創建新文件。第二個 echo 語句使用兩個 >> 將數據附加到現有文件的後面。順便說一下,如果該文件不存在,那麼會創建一個文件。


16. 在執行腳本的過程中提供反饋
最好在腳本中包含 echo 語句以表明它執行的邏輯進展狀況。可以添加一些能迅速表明輸出目的的語句。


如果腳本要花費一些時間執行,那或許應在執行腳本的開始和結束的地方列印時間。這樣可以計算出所花費的時間。


在腳本樣本中,一些提供進展說明的 echo 語句如下所示:

源碼:--------------------------------------------------------------------------------
# --------------------------------------------
echo "Subject: Product X, FVT testing"
dateTest=`date`
echo "Begin testing at: $dateTest"
echo ""
echo "Testcase: $CALLER"
echo ""
# --------------------------------------------

# --------------------------------------------
echo ""
echo "Listing files..."
# --------------------------------------------

# The following file should be listed:
ListFile $HOME/.profile

...

# --------------------------------------------
echo ""
echo "Creating file 1"
# --------------------------------------------
--------------------------------------------------------------------------------


17. 提供腳本執行的摘要
如果正在計算錯誤或失敗事務的次數,那最好表明是否有錯誤。此方法使得測試者在看到輸出文件的最後能迅速地辨認出是否存在錯誤。


在下面的腳本示例中,代碼語句提供了上述腳本的執行摘要:

源碼:--------------------------------------------------------------------------------
# --------------
# Exit
# --------------
if [ $errorCounter -ne 0 ]
then
echo ""
echo "*** $errorCounter ERRORS found during ***"
echo "*** the execution of this test case. ***"
terminate
else
echo ""
echo "*** Yeah! No errors were found during ***"
echo "*** the execution of this test case. Yeah! ***"
fi

echo ""
echo "$CALLER complete."
echo ""
dateTest=`date`
echo "End of testing at: $dateTest"
echo ""

exit 0

# end of file
--------------------------------------------------------------------------------

18. 提供一個容易解釋的輸出文件
在腳本生成的實際輸出中提供一些關鍵信息是非常有用的。那樣,測試者就可以很容易地確定正在查看的文件是否與自己所做的相關以及它是否是當前產生的。附加的時間戳記對於是否是當前狀態是很重要的。摘要報告對於確定是否有錯誤也是很有幫助的;如果有錯誤,那麼測試者就必須搜索指定的關鍵字,例如 ERROR,並確認出個別失敗的事務。

以下是一段輸出文件樣本的片段:

源碼:--------------------------------------------------------------------------------
Subject: CMVC 2.3.1, FVT testing, Common, Part 1
Begin testing at: Tue Apr 18 12:50:55 EDT 2000

Database: DB2
Family: cmpc3db2
Testcase: fvt-common-1

Creating Users...
User pat was created successfully.
...

Well done! No errors were found during the
execution of this test case

fvt-common-1 complete.

End of testing at: Tue Apr 18 12:56:33 EDT 2000
--------------------------------------------------------------------------------

當遇到錯誤時輸出文件最後部分的示例如下所示:


源碼:--------------------------------------------------------------------------------
ERROR found in Report -view DefectView

*** 1 ERRORS found during the execution of this test case. ***
The populate action for the CMVC family was not successful.
Recreating the family may be necessary before
running fvt-client-3 again, that is, you must use 'rmdb',
'rmfamily', 'mkfamily' and 'mkdb -d',
then issue: fvt-common-1 and optionally, fvt-server-2.
fvt-client-3 terminated, exiting now with rc=1.
End of testing at: Wed Jan 24 17:06:06 EST 2001
--------------------------------------------------------------------------------


19. 如有可能,提供清除腳本及返回基準線的方法
測試腳本可以生成臨時文件;假若這樣,最好能讓腳本刪除所有臨時文件。這就會避免由於測試者也許沒有刪除所有臨時文件而引起的錯誤,更糟糕的是將所需要的文件當作臨時文件而刪除了。

運行功能測試的 Bash shell 腳本
本節描述如何運用 Bash shell 腳本進行功能測試。假設您已經執行了在前面部分中所述步驟。


設置必要的環境變數
根據需要在 .profile 中或手工指定下列環境變數。該變數用於說明在腳本中如何處理,所需環境變數的驗證必須在腳本執行前定義。

export TEST_VAR=1

將 Bash shell 腳本複製到正確的目錄下
Bash shell 腳本和相關文件需要複製到要進行功能測試的用戶標識的目錄結構下。

登錄進某個帳戶。您應該在主目錄下。假設它是 /home/tester。
為測試案例創建目錄:mkdir fvt
複製 Bash shell 腳本和相關文件。獲取壓縮文件(請參閱參考資料)並將其放在 $HOME 下。然後將其按下列方式解壓:unzip trfvtbash.zip
為了執行這個文件,更改文件的許可權:chmod u+x *
更改名稱以除去文件的後綴:mv test-bucket-1.bash test-bucket-1

運行腳本
執行下列步驟以運行腳本:

以測試者的用戶標識登錄
更改目錄至所複製腳本的位置:cd $HOME/fvt
從 $HOME/fvt 運行腳本:./test-bucket-1 -s 2>&1 | tee test-bucket-1.out
看一下輸出文件 "test-bucket-1.out" 的尾部並查看摘要報告的結論

[火星人 ] bash 經典 <收藏>已經有674次圍觀

http://coctec.com/docs/linux/show-post-136456.html