歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux資訊 >> 更多Linux >> Bash 實例 (2)

Bash 實例 (2)

日期:2017/2/27 9:26:23   编辑:更多Linux
  在前一篇 bash 的介紹性文章中,Daniel Robbins 為您講解了腳本語言的一些基本元素和使用 bash 的原因。在本文(即第二部分)中,Daniel 繼續前一篇的內容,並講解條件 (if-then) 語句、循環和更多的 bash 基本結構。  我們先看一下處理命令行自變量的簡單技巧,然後再看看 bash 基本編程結構。  接收自變量  在 介紹性文章中的樣本程序中,我們使用環境變量 "$1" 來引用第一個命令行自變量。類似地,可以使用 "$2"、"$3" 等來引用傳遞給腳本的第二和第三個自變量。這裡有一個例子:  #!/usr/bin/env bash  echo name of script is $0  echo first argument is $1  echo second argument is $2  echo seventeenth argument is $17  echo number of arguments is $#  除以下兩個細節之外,此例無需說明。第一,"$0" 將擴展成從命令行調用的腳本名稱,"$#" 將擴展成傳遞給腳本的自變量數目。試驗以上腳本,通過傳遞不同類型的命令行自變量來了解其工作原理。  有時需要一次引用所有命令行自變量。針對這種用途,bash 實現了變量 "$@",它擴展成所有用空格分開的命令行參數。在本文稍後的 "for" 循環部分中,您將看到使用該變量的例子。  Bash 編程結構  如果您曾用過如 C、Pascal、Python 或 Perl 那樣的過程語言編程,則一定熟悉 "if" 語句和 "for" 循環那樣的標准編程結構。對於這些標准結構的大多數,Bash 有自己的版本。在下幾節中,將介紹幾種 bash 結構,並演示這些結構和您已經熟悉的其它編程語言中結構的差異。如果以前編程不多,也不必擔心。我提供了足夠的信息和示例,使您可以跟上本文的進度。  方便的條件語句  如果您曾用 C 編寫過與文件相關的代碼,則應該知道:要比較特定文件是否比另一個文件新需要大量工作。那是因為 C 沒有任何內置語法來進行這種比較,必須使用兩個 stat() 調用和兩個 stat 結構來進行手工比較。相反,bash 內置了標准文件比較運算符,因此,確定“/tmp/myfile 是否可讀”與查看“$myvar 是否大於 4”一樣容易。  下表列出最常用的 bash 比較運算符。同時還有如何正確使用每一選項的示例。示例要跟在 "if" 之後。例如:  if [ -z "$myvar" ]  then   echo "myvar is not defined"  fi  運算符 描述 示例   文件比較運算符   -e filename 如果 filename 存在,則為真 [ -e /var/log/syslog ]   -d filename 如果 filename 為目錄,則為真 [ -d /tmp/mydir ]   -f filename 如果 filename 為常規文件,則為真 [ -f /usr/bin/grep ]   -L filename 如果 filename 為符號鏈接,則為真 [ -L /usr/bin/grep ]   -r filename 如果 filename 可讀,則為真 [ -r /var/log/syslog ]   -w filename 如果 filename 可寫,則為真 [ -w /var/mytmp.txt ]   -x filename 如果 filename 可執行,則為真 [ -L /usr/bin/grep ]   filename1 -nt filename2 如果 filename1 比 filename2 新,則為真 [ /tmp/install/etc/services -nt /etc/services ]   filename1 -ot filename2 如果 filename1 比 filename2 舊,則為真 [ /boot/bzImage -ot arch/i386/boot/bzImage ]   字符串比較運算符 (請注意引號的使用,這是防止空格擾亂代碼的好方法)   -z string 如果 string 長度為零,則為真 [ -z "$myvar" ]   -n string 如果 string 長度非零,則為真 [ -n "$myvar" ]   string1 = string2 如果 string1 與 string2 相同,則為真 [ "$myvar" = "one two three" ]   string1 != string2 如果 string1 與 string2 不同,則為真 [ "$myvar" != "one two three" ]   算術比較運算符   num1 -eq num2 等於 [ 3 -eq $mynum ]   num1 -ne num2 不等於 [ 3 -ne $mynum ]   num1 -lt num2 小於 [ 3 -lt $mynum ]   num1 -le num2 小於或等於 [ 3 -le $mynum ]   num1 -gt num2 大於 [ 3 -gt $mynum ]   num1 -ge num2 大於或等於 [ 3 -ge $mynum ]   有時,有幾種不同方法來進行特定比較。例如,以下兩個代碼段的功能相同:  if [ "$myvar" -eq 3 ]  then   echo "myvar equals 3"  fi  if [ "$myvar" = "3" ]  then   echo "myvar equals 3"  fi  上面兩個比較執行相同的功能,但是第一個使用算術比較運算符,而第二個使用字符串比較運算符。  字符串比較說明  大多數時候,雖然可以不使用括起字符串和字符串變量的雙引號,但這並不是好主意。為什麼呢?因為如果環境變量中恰巧有一個空格或制表鍵,bash 將無法分辨,從而無法正常工作。這裡有一個錯誤的比較示例:  if [ $myvar = "foo bar oni" ]  then   echo "yes"  fi  在上例中,如果 myvar 等於 "foo",則代碼將按預想工作,不進行打印。但是,如果 myvar 等於 "foo bar oni",則代碼將因以下錯誤失敗:  [: too many arguments  在這種情況下,"$myvar"(等於 "foo bar oni")中的空格迷惑了 bash。bash 擴展 "$myvar" 之後,代碼如下:  [ foo bar oni = "foo bar oni" ]  因為環境變量沒放在雙引號中,所以 bash 認為方括號中的自變量過多。可以用雙引號將字符串自變量括起來消除該問題。請記住,如果養成將所有字符串自變量用雙引號括起的習慣,將除去很多類似的編程錯誤。"foo bar oni" 比較應該寫成:  if [ "$myvar" = "foo bar oni" ]  then   echo "yes"  fi  更多引用細節  如果要擴展環境變量,則必須將它們用雙引號、而不是單引號括起。單引號 禁用變量(和歷史)擴展。  以上代碼將按預想工作,而不會有任何令人不快的意外出現。  循環結構:"for"  好了,已經講了條件語句,下面該探索 bash 循環結構了。我們將從標准的 "for" 循環開始。這裡有一個簡單的例子:  #!/usr/bin/env bash  for x in one two three four  do  echo number $x  done  輸出:  number one  number two   number three   number four  發生了什麼?"for" 循環中的 "for x" 部分定義了一個名為 "$x" 的新環境變量(也稱為循環控制變量),它的值被依次設置為 "one"、"two"、"three" 和 "four"。每一次賦值之後,執行一次循環體("do" 和 "done" 之間的代碼)。在循環體內,象其它環境變量一樣,使用標准的變量擴展語法來引用循環控制變量 "$x"。還要注意,"for" 循環總是接收 "in" 語句之後的某種類型的字列表。在本例中,指定了四個英語單詞,但是字列表也可以引用磁盤上的文件,甚至文件通配符。看看下面的例子,該例演示如何使用標准 shell 通配符:  #!/usr/bin/env bash  for myfile in /etc/r*  do  if [ -d "$myfile" ]   then   echo "$myfile (dir)"  else  echo "$myfile"  fi  done  輸出:  /etc/rc.d (dir)  /etc/resolv.conf  /etc/resolv.conf~  /etc/rpc   以上代碼列出在 /etc 中每個以 "r" 開頭的文件。要做到這點,bash 在執行循環之前首先取得通配符 /etc/r*,然後擴展它,用字符串 /etc/rc.d /etc/resolv.conf /etc/resolv.conf~ /etc/rpc 替換。一旦進入循環,根據 myfile 是否為目錄,"-d" 條件運算符用來執行兩個不同操作。如果是目錄,則將 "(dir)" 附加到輸出行。  還可以在字列表中使用多個通配符、甚至是環境變量:  for x in /etc/r??? /var/lo* /home/drobbins/mystuff/* /tmp/${MYPATH}/*  do  cp $x /mnt/mydir  done  Bash 將在所有正確位置上執行通配符和環境變量擴展,並可能創建一個非常長的字列表。  雖然所有通配符擴展示例使用了絕對路徑,但也可以使用相對路徑,如下所示:  for x in ../* mystuff/*  do  echo $x is a silly file  done  在上例中,bash 相對於當前工作目錄執行通配符擴展,就象在命令行中使用相對路徑一樣。研究一下通配符擴展。您將注意到,如果在通配符中使用絕對路徑,bash 將通配符擴展成一個絕對路徑列表。否則,bash 將在後面的字列表中使用相對路徑。如果只引用當前工作目錄中的文件(例如,如果輸入 "for x in *"),則產生的文件列表將沒有路徑信息的前綴。請記住,可以使用 "basename" 可執行程序來除去前面的路徑信息,如下所示:  for x in /var/log/*  do  echo `basename $x` is a file living in /var/log  done  當然,在腳本的命令行自變量上執行循環通常很方便。這裡有一個如何使用本文開始提到的 "$@" 變量的例子:  #!/usr/bin/env bash  for thing in "$@"  do  echo you typed ${thing}.  done  輸出:  $ allargs hello there you silly  you typed hello.  you typed there.  you typed you.  you typed silly.  Shell 算術  在學習另一類型的循環結構之前,最好先熟悉如何執行 shell 算術。是的,確實如此:可以使用 shell 結構來執行簡單的整數運算。只需將特定的算術表達式用 "$((" 和 "))" 括起,bash 就可以計算表達式。這裡有一些例子:  $ echo $(( 100 / 3 ))  33  $ myvar="56"  $ echo $(( $myvar + 12 ))  68  $ echo $(( $myvar - $myvar ))  0 $ myvar=$(( $myvar + 1 ))  $ echo $myvar  57  您已經熟悉如何執行數學操作,現在該介紹其它




Copyright © Linux教程網 All Rights Reserved