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

 3>在Shell中使用數據變量

  用戶能夠在Shell中使用數據變量,例如ba.sh程序:shell

  cd/usr/icewalk編程

  ls|cpio -o > /dev/fd0小程序

  該程序中要備份的目錄爲一常量,即該程序只能用來備份一個目錄。若在該程序中使用變量,則會使其更通用:學習

  workdir=$1測試

  cd $workdirspa

  ls * |cpio -o > /dev/fd0命令行

  經過這一改變,用戶可使用程序備份變量$workdir指定的目錄。例如咱們要備份/home/www的內容,只要運行ba.sh /home/www便可實現。(若不明白 $1,下面將詳細介紹shell參數的傳遞,$1表明本sh程序-ba.sh的第一個參數)設計

  4>在Shell程序中加上註釋rem

  爲了增長程序的可讀性,咱們提倡加入註釋。在Shell程序中註釋將以"#"號開始。當Shell解釋到"#"時,會認爲從"#"號起一直到該行行尾爲註釋。字符串

  5>對Shell變量進行算術運算

  高級語言中變量是具備類型的,即變量將被限制爲某一數據類型,如整數或字符類型。Shell變量一般按字符進行存儲,爲了對Shell變量進行算術運算,必須使用expr命令。

  expr命令將把一個算術表達式做爲參數,一般形式以下:

  expr [數字] [操做符] [數字]

  因爲Shell是按字符形式存儲變量的,因此用戶必須保證參加算術運算的操做數必須爲數值。下面是有效的算術操做符:

  + 兩個整數相加

  - 第一個數減去第二個數

  * 兩整數相乘

  / 第一個整數除以第二個整數

  % 兩整數相除,取餘數

  例如:

  $expr 2 + 1

  結果顯示:3

  $expr 5 - 3

  結果顯示:2

  若expr的一個參數是變量,那麼在表達式計算以前用變量值替換變量名。

  $int=3

  $expr $int + 4

  結果顯示:7

  用戶不能單純使用"*"作乘法,若輸入:

  $expr 4*5

  系統將會報錯,由於Shell看到"*"將會首先進行文件名替換。正確形式爲:

  $expr 4 \* 5

  結果顯示:20

  多個算術表達式能夠組合在一塊兒,例如:

  $expr 5 + 7 / 3

  結果顯示:7

  運算次序是先乘除後加減,若要改變運算次序,必須使用"`"號,如:

  $int=`expr 5 + 7`

  $expr $int/3

  結果顯示:4

  或者:

  $expr `expr 5+7`/3

  結果顯示:4

  6>向Shell程序傳遞參數

  一個程序可使用兩種方法得到輸入數據。一是執行時使用參數。另外一種方法是交互式地得到數據。vi編輯程序能夠經過交互式的方法得到數據,而ls和 expr則從參數中取得數據。以上兩種方法Shell程序均可以使用。在"交互式讀入數據"一節中將介紹Shell程序經過交互式的方法得到參數。

  經過命令行給Shell程序傳遞參數能夠擴大程序的用途。之前面提到的ba.sh程序爲例:

  $cat >re.sh

  cd $workdir

  cpio -i < /dev/fd0

  ^d

  程序re.sh恢復了ba.sh程序備份的全部文件。若只從軟盤上恢復一個指定的文件,能夠用該文件名做爲參數,傳遞給Shell程序re.sh:

  程序改寫以下:

  $cat >re2.sh

  cd $workdir

  cpio -i $1 < /dev/fd0

  ^d

  用戶能夠指定要恢復的文件,例如fname

  $re2.sh fname

  此時文件fname做爲第一個位置參數傳遞給re2.sh,re2.sh的缺點是要恢復兩個或多個文件要重複運行,咱們能夠用$*變量傳遞不肯定的參數給程序:

  $cat >re3.sh

  cd $workdir

  cpio -i $* < /dev/fd0

  ^d

  咱們就能夠恢復多個文件,例如fname1,fname2,fname3

  $re3.sh fname1 fname2 fname3

  (以上程序re.sh,re2.sh,re3.sh,假設用戶已經chmod了可執行權利)

  由於沒有賦值的變量能夠做爲NULL看待,因此如果程序re3.sh在執行時候沒賦予參數,那麼一個空值將被插入到cpio命令中。該命令將恢復全部保存的文件。

  條件判斷語句

  條件判斷語句是程序設計語言中十分重要的語句,該語句的含義是當某一條件知足時,執行指定的一組命令。

  1>if - then語句

  格式: if command1

  then

  command2

  command3

  fi ---(if 語句結束)

  command4

  每一個程序或命令執行結束後都有一個返回的狀態,用戶能夠用Shell變量$?得到這一狀態。if語句檢查前面命令執行的返回狀態,若該命令成功執行,那麼 在then和fi之間的命令都將被執行。在上面的命令序列中,command1和command4總要執行。若command1成功執 行,command2和command3也將執行。

  請看下面程序:

  #unload -program to backup and remove files

  cd $1

  ls -a | cpio -o > /dev/mnt0

  rm *

  該程序在備份資料後,刪除檔案,但當cpio命令不能成功執行時,rm命令仍是把資料刪除了,咱們可不但願這樣,爲了不此狀況,能夠用if - then語句:

  #--卸載和判斷刪除程序

  cd $1

  if ls -a | cpio > /dev/mnt0

  then

  rm *

  fi

  上面程序在cpio執行成功後才刪除檔案

  同時,若執行沒有成功,咱們但願獲得提示,sh中的echo命令能夠向用戶顯示消息,並顯示後換行,上面程序能夠寫成:

  #--卸載和判斷刪除程序

  cd $1

  if ls -a | cpio > /dev/mnt0

  then

  echo "正刪除文件資料... ..."

  rm *

  fi

  echo命令可使用一些特殊的逃逸字符進行格式化輸出,下面是這些字符及其含義:

  \b Backspace

  \c 顯示後不換行

  \f 在終端上屏幕的開始處顯示

  \n 換行

  \r 回車

  \t 製表符

  \v 垂直製表符

  \ 反斜框

  \0nnn 用1,2或3位8進制整數表示一個ASCII碼字符

  2>if - then - else語句

  不用多說它的做用,別的高級語言中都有,格式爲:

  if command1

  then

  command2

  command3

  else

  command4

  command5

  fi

  在此結構中,command1中是先執行,當command1成功執行時,將執行command2和command3,不然執行command4和command5

  注意看下面程序:

  #備份程序

  cd $1

  if ls -a |cpio -o > /dev/mnt0

  then

  echo "刪除源資料... ..."

  rm *

  else

  echo "磁帶備份失敗!"

  fi

  3>test命令進行條件測試

  if語句能夠經過測試命令執行的返回狀態來控制命令的執行,若要測試其餘條件,在bsh中可使用test命令。該命令檢測某一條件,當條件爲真時返回 0,不然返回非0值。test命令可使Shell程序中的if語句象其餘程序語言中的條件判斷語句同樣,具備很強的功能。

  test命令的使用方法爲:

  test condition

  可測試的條件分爲4類:

  1)測試兩個字符串之間的關係。

  2)測試兩個整數之間關係。

  3)測試文件是否存在或是否具備某種狀態或屬性。

  4)測試多個條件的與(and)或(or)組合。

  一、條件語句>>test語句

  1>測試字符串間的關係

  bsh把全部的命令行和變量都看做字符串。一些命令如expr和test能夠把字符看成數字進行操做。

  一樣任何數字也能夠做爲字符串進行操做。

  用戶能夠比較兩個字符串相等或不等,也能夠測試一個串是否賦了值。有關串的操做符以下:

  str1 = str2 當兩個串有相同內容、長度時爲真

  str1 != str2 當串str1和str2不等時爲真

  -n str1 當串的長度大於0時爲真(串非空)

  -z str1 當串的長度爲0時爲真(空串)

  str1 當串str1爲非空時爲真

  不但Shell程序可使用test進行條件判斷,test命令也能夠獨立執行,如:

  $str1=abcd

  $test $str1 = abcd

  $echo $?

  結果顯示:0

  與上例中第一行賦值語句中的等號不一樣,test命令中的等號兩邊必需要有空格。本例test命令共有3個參數。注意兩個串相等必須是長度和內容都相等。

  $str1="abcd "

  $test "$str1" = abcd

  $echo $?

  結果顯示:1

  上面str1包含5個字符,其中最後一個爲空格符。而test命令中的另外一個串只有4個字符,因此兩串不等,test返回1。

  不帶任何操做符和使用-n操做符測試一個串結果是同樣的,例如:

  $str1=abce

  $test $str1

  $echo $?

  結果顯示:0

  $test -n $str1

  $echo $?

  結果顯示:0

  可是,上面兩條命令也有一點差異,反映出了使用test命令潛在的問題,請看下例:

  $str1=" "

  $test $str1

  $echo $?

  結果顯示:1

  $test -n "$str1"

  $echo $?

  結果顯示:0

  $test -n $str1

  結果顯示:test:argument expected

  上例中,第一次測試爲假由於Shell在執行命令行以前首先要進行變量替換,即把$str1換成空格,而後shell又將命令行上的空格刪除,故test 命令測試到的爲空串。而在第二次測試中,變量替換後空格位於括號內,故不會被刪除,test測試到的是一個包含空格的串,在第三次測試中,shell把空 格刪除,只把-n傳個test命令,因此顯示參數錯。

  2>測試兩個整數之間關係

  test命令與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爲真

  下面的例子反映了字符串比較與數字比較的不一樣:

  $str1=1234

  $str2=01234

  $test $str1 = $str2

  $echo $?

  結果顯示:1

  $test $str1 -eq $str2

  $echo $?

  結果顯示:0

  3>有關文件的測試

  使用test進行的第三類測試是測試文件的狀態,用戶能夠測試文件是否存在,是否可寫以及其餘文件屬性。下面是文件測試時使用的選項。注意只有文件存在時,纔有可能爲真。

  -r file 用戶可讀爲真

  -w file 用戶可寫爲真

  -x file 用戶可執行爲真

  -f file 文件爲正規文件爲真

  -d file 文件爲目錄爲真

  -c file 文件爲字符特殊文件爲真

  -b file 文件爲塊特殊文件爲真

  -s file 文件大小非0時爲真

  -t file 當文件描述符(默認爲1)指定的設備爲終端時爲真

  4>複雜的條件測試(and 、or 、not)

  -a 與

  -o 或

  ! 非

  就是組合條件了,任何高級語言中都有的(NOT 、AND 、OR),例如:

  $test -r em.null -a -s em.null

  $echo $?

  結果顯示:1

  說明了em.null並非可讀而且非空的文件

  5>另外一種執行test的方法

  bsh中還有另外一種執行test命令的方法,就是把測試條件放到一對[ ]中,例如:

  $int1=4

  $[ $int1 -gt 2 ]

  $echo $?

  結果顯示:0

  要注意在[ 的後面和 ]符號的前面要有一個空格。

  下面咱們用test命令寫個簡單但比較完善的程序:

  #-- 備份程序

  #-- 檢查參數

  if [ $# -ne 1 ]

  then

  echo "請在程序名後面指出要備份文件所在目錄!"

  exit 1

  fi

  #-- 檢查目錄名是否有效

  if [ !-d "$1" ]

  then

  echo "$1 不是一個目錄!"

  exit 2

  fi

  cd $1

  ls -a | cpio -o >/dev/mnt0

  if [ $? -eq 0 ]

  then

  rm *

  else

  echo "cpio執行不成功!備份失敗..."

  exit 3

  fi

  6>空命令

  在Bsh中用 : 表明空命令,就是充個數,什麼都不作

  7>嵌套if語句和elif結構

  檢查條件1

  A:當條件1爲真,則執行一部分操做

  B:若條件1爲假,檢查條件2

  1)若條件2爲真,執行另一部分操做

  2)若條件2爲假,檢查條件3

  3)若條件3爲真,執行其餘一部分操做

  語法以下:

  if command

  then

  command

  else

  if command

  then

  command

  else

  if command

  then

  command

  fi

  fi

  fi

  8>elif語句

  嵌套if語句有時會給用戶帶來混亂,特別是何時fi語句很難判斷。所以Bourne Shell又提供了elif語句。elif是else-if的縮寫,它表示是if語句的繼續。格式爲:

  if command

  then

  command

  elif command

  then

  command

  elif command

  then

  command

  fi

  上面介紹的嵌套if語句和elif語句完成相同的功能,用戶能夠根據本身的喜愛選擇一種使用。

  9>case語句

  前面說的elif語句替代if-then-else語句,但有時在編程時還會遇到對同一變量進行屢次的測試,該狀況能夠用多個elif語句實現,但還有一種更簡單的方法就是用case語句。

  case語句不但取代了多個elif和then語句,還能夠用變量值對多個模式進行匹配,當某個模式與變量值匹配後,其後的一系列命令將被執行,下面是case語句使用的語句。

  case value in

  pattem 1)

  command

  command;;

  pattem 2)

  command

  command;;

  ....

  pattem)

  command;

  esac

  case語句只執行其中的一組命令,當變量值與多個模式相匹配時,只有第一個匹配的模式對應的命令被執行。";;"表示該模式對應的命令部分程序。

  經過學習下面的read語句,咱們們再舉例子說明case語句的用法。

  10>read語句

  Shell程序不但能夠經過命令行參數獲得輸入數據,還可使用read命令提示用戶輸入數據,其語法格式爲:

  read var1 var2... ...varn

  當Bsh遇到一個read語句時,在標準輸入文件中讀取數據直到一個換行符。此時Shell在解釋輸入行時,不進行文件名或變量的替換,只是簡單地刪除多 餘的空格。而後Shell將輸入行的第一個字的內容給變量1,第二個給變量2,直到全部變量都賦上值或是輸入行爲空。若輸入行中字的個數超過變量個 數,Shell將把輸入行中剩餘的全部字的內容都賦給最後一個變量。當變量個數多於輸入行字的個數時候,多於的變量將賦一個空值。輸入行的每個字是由空 格分隔的一個字母和數字組成的字符串。

  $read var1 var2 var3

  輸入:Hello my friend

  $echo $var1 $var2 $var3

  結果顯示:Hello my friend

  $echo $var2

  結果顯示:my

  下面用個read和case的例子結束本部分的學習:

  #--交互式備份,恢復程序

  echo "輸入要備份文件所在目錄:\c"

  read WORKDIR

  if [ !-d $WORKDIR ]

  then

  echo "Sorry,$WORKDIR is not a directory"

  exit 1

  fi

  cd $WORKDIR

  echo "輸入選擇:"

  echo _

  echo "1.恢復到 $WORKDIR"

  echo "2.備份 $WORKDIR"

  echo "0.退出"

  echo

  echo "\c"

  read CHOICE

  case "$CHOICE" in

  1)echo "恢復中... ..."

  cpio -i < /dev/mnt0;;

  2)echo "備份中... ..."

  ls | cpio -o > /dev/mnt0;;

  0)exit 1

  *)exit 1

  esac

  if [ $? -ne 0 ]

  then

  echo "程序運行中出現錯誤!"

  else

  echo "操做成功!"

  fi

  在上面代碼中,"*"定義了其餘模式下不匹配時的默認操做。

  循環語句

  前面介紹的程序和所學的語句都是從頭至尾成一條主線下來,或是成分支結構,在平常管理UNIX的過程當中,常常要重複的作一些操做,處理批量的問題,這就涉及到了循環結構,同高級語言類似,UNIX的Shell也提供了強大的循環處理語句。

  Bsh語言中有三種循環語句-while循環、until循環、for循環,下面經過具體的例子分別介紹這三種結構。

  While循環

  在while循環語句中,當某一條件爲真時,執行指定的命令。語句的結構以下:

  while command

  do

  command

  command

  … …

  done

  示例代碼以下:

  #測試while循環小程序

  x_t=1

  while [ $x_t -lt 5 ]

  do

  mm=` expr $x_t \* $int ` #注意"\"的做用

  echo "$mm"

  x_t=` expr $x_t + 1 ` #注意expr的用法

  done

  echo "THE WHILE IS END!\n"

  程序的執行結果以下:

  1

  4

  9

  16

  THE WHILE IS END

  在上述程序中,當變量x_t的值小於5的時候,執行while循環中的語句。在第五次循環時, [ $x_t-lt5]命令返回非零值,因而程序執行done後面的代碼。

  如今利用while循環,能夠改進咱們早些時候用的備份數據的例子,當用戶指定的目錄備份完畢後,使用while循環使程序執行一次能夠備份多個用戶指定的目錄。代碼以下:

  echo "歡迎使用備份小程序"

  ANS=Y

  while [ $ANS = Y -o $ANS = y ]

  do

  echo _

  #讀目錄名

  echo "輸入要備份的目錄名:\c"

  read DIR

  if [ ! -d $DIR ]

  then

  echo "$DIR不是一個目錄!"

  exit 1

  fi

  cd $DIR

  echo "請選擇:"

  echo _

  echo "1 恢復數據到 $DIR"

  echo "2 備份$DIR的數據"

  echo

  echo "請選擇:\c"

  read CHOICE

  case "$CHOICE" in

  1) echo "恢復中… …"

  cpio -i 2) echo "備份中… …"

  cpio -o >/dev/rmt0;;

  *) echo "選擇無效"

  esac

  if [ $? -ne 0 ]

  then

  echo "cpio執行過程當中出現問題"

  exit 2

  fi

  echo "繼續別的目錄嗎?(Y/y)\c"

  read ANS

  done

  在程序開始,咱們給變量ANS符值爲Y,根據whlie的判斷條件,程序進入while循環,執行do-done中的語句,每次循環都要求用戶輸入ANS 的值用來判斷是否進行下次重複執行do-done中的語句。若是用戶輸入的條件不知足while語句條件,循環結束,程序執行done後面的語句。

相關文章
相關標籤/搜索