青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

攀升·Uranus


Something Different,Something New
數據加載中……

(轉)Bash 實例,第 2 部分

 

轉載:http://www.ibm.com/developerworks/cn/linux/shell/bash/bash-2/

 

Bash 實例,第 2 部分

更多的 bash 基本編程

級別: 初級

Daniel Robbins (drobbins@gentoo.org), 總裁兼 CEO, Gentoo Technologies, Inc.

2000 年 4 月 01 日

在前一篇 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 如果 filename1filename2新,則為真 [ /tmp/install/etc/services -nt /etc/services ]
filename1-ot filename2 如果 filename1filename2舊,則為真 [ /boot/bzImage -ot arch/i386/boot/bzImage ]
字符串比較運算符 (請注意引號的使用,這是防止空格擾亂代碼的好方法)
-z string 如果 string長度為零,則為真 [ -z "$myvar" ]
-n string 如果 string長度非零,則為真 [ -n "$myvar" ]
string1= string2 如果 string1string2相同,則為真 [ "$myvar" = "one two three" ]
string1!= string2 如果 string1string2不同,則為真 [ "$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",則代碼將因以下錯誤失?。?/p>
 [: 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
                        





回頁首


更多的循環結構:"while" 和 "until"

只要特定條件為真,"while" 語句就會執行,其格式如下:

 while [ condition ]
                        do
                        statements
                        done
                        

通常使用 "While" 語句來循環一定次數,比如,下例將循環 10 次:

 myvar=0
                        while [ $myvar -ne 10 ]
                        do
                        echo $myvar
                        myvar=$(( $myvar + 1 ))
                        done
                        

可以看到,上例使用了算術表達式來使條件最終為假,并導致循環終止。

"Until" 語句提供了與 "while" 語句相反的功能:只要特定條件為 ,它們就重復。下面是一個與前面的 "while" 循環具有同等功能的 "until" 循環:

 myvar=0
                        until [ $myvar -eq 10 ]
                        do
                        echo $myvar
                        myvar=$(( $myvar + 1 ))
                        done
                        





回頁首


Case 語句

Case 語句是另一種便利的條件結構。這里有一個示例片段:

                        case "${x##*.}" in
                        gz)
                        gzunpack ${SROOT}/${x}
                        ;;
                        bz2)
                        bz2unpack ${SROOT}/${x}
                        ;;
                        *)
                        echo "Archive format not recognized."
                        exit
                        ;;
                        esac
                        

在上例中,bash 首先擴展 "${x##*.}"。在代碼中,"$x" 是文件的名稱,"${x##.*}" 除去文件中最后句點后文本之外的所有文本。然后,bash 將產生的字符串與 ")" 左邊列出的值做比較。在本例中,"${x##.*}" 先與 "gz" 比較,然后是 "bz2",最后是 "*"。如果 "${x##.*}" 與這些字符串或模式中的任何一個匹配,則執行緊接 ")" 之后的行,直到 ";;" 為止,然后 bash 繼續執行結束符 "esac" 之后的行。如果不匹配任何模式或字符串,則不執行任何代碼行,在這個特殊的代碼片段中,至少要執行一個代碼塊,因為任何不與 "gz" 或 "bz2" 匹配的字符串都將與 "*" 模式匹配。





回頁首


函數與名稱空間

在 bash 中,甚至可以定義與其它過程語言(如 Pascal 和 C)類似的函數。在 bash 中,函數甚至可以使用與腳本接收命令行自變量類似的方式來接收自變量。讓我們看一下樣本函數定義,然后再從那里繼續:

                        tarview() {
                        echo -n "Displaying contents of $1 "
                        if [ ${1##*.} = tar ]
                        then
                        echo "(uncompressed tar)"
                        tar tvf $1
                        elif [ ${1##*.} = gz ]
                        then
                        echo "(gzip-compressed tar)"
                        tar tzvf $1
                        elif [ ${1##*.} = bz2 ]
                        then
                        echo "(bzip2-compressed tar)"
                        cat $1 | bzip2 -d | tar tvf -
                        fi
                        }
                        

另一種情況

可以使用 "case" 語句來編寫上面的代碼。您知道如何編寫嗎?

我們在上面定義了一個名為 "tarview" 的函數,它接收一個自變量,即某種類型的 tar 文件。在執行該函數時,它確定自變量是哪種 tar 文件類型(未壓縮的、gzip 壓縮的或 bzip2 壓縮的),打印一行信息性消息,然后顯示 tar 文件的內容。應該如下調用上面的函數(在輸入、粘貼或找到該函數后,從腳本或命令行調用它):

 $ tarview shorten.tar.gz
                        Displaying contents of shorten.tar.gz (gzip-compressed tar)
                        drwxr-xr-x ajr/abbot         0 1999-02-27 16:17 shorten-2.3a/
                        -rw-r--r-- ajr/abbot      1143 1997-09-04 04:06 shorten-2.3a/Makefile
                        -rw-r--r-- ajr/abbot      1199 1996-02-04 12:24 shorten-2.3a/INSTALL
                        -rw-r--r-- ajr/abbot       839 1996-05-29 00:19 shorten-2.3a/LICENSE
                        ....
                        

交互地使用它們

別忘了,可以將函數(如上面的函數)放在 ~/.bashrc 或 ~/.bash_profile 中,以便在 bash 中隨時使用它們。

如您所見,可以使用與引用命令行自變量同樣的機制來在函數定義內部引用自變量。另外,將把 "$#" 宏擴展成包含自變量的數目。唯一可能不完全相同的是變量 "$0",它將擴展成字符串 "bash"(如果從 shell 交互運行函數)或調用函數的腳本名稱。





回頁首


名稱空間

經常需要在函數中創建環境變量。雖然有可能,但是還有一個技術細節應該了解。在大多數編譯語言(如 C)中,當在函數內部創建變量時,變量被放置在單獨的局部名稱空間中。因此,如果在 C 中定義一個名為 myfunction 的函數,并在該函數中定義一個名為 "x" 的自變量,則任何名為 "x" 的全局變量(函數之外的變量)將不受它的印象,從而消除了負作用。

在 C 中是這樣,但在 bash 中卻不是。在 bash 中,每當在函數內部創建環境變量,就將其添加到 全局名稱空間。這意味著,該變量將重寫函數之外的全局變量,并在函數退出之后繼續存在:

 #!/usr/bin/env bash
                        myvar="hello"
                        myfunc() {
                        myvar="one two three"
                        for x in $myvar
                        do
                        echo $x
                        done
                        }
                        myfunc
                        echo $myvar $x
                        

運行此腳本時,它將輸出 "one two three three",這顯示了在函數中定義的 "$myvar" 如何影響全局變量 "$myvar",以及循環控制變量 "$x" 如何在函數退出之后繼續存在(如果 "$x" 全局變量存在,也將受到影響)。

在這個簡單的例子中,很容易找到該錯誤,并通過使用其它變量名來改正錯誤。但這不是正確的方法,解決此問題的最好方法是通過使用 "local" 命令,在一開始就預防影響全局變量的可能性。當使用 "local" 在函數內部創建變量時,將把它們放在 局部名稱空間中,并且不會影響任何全局變量。這里演示了如何實現上述代碼,以便不重寫全局變量:

                        #!/usr/bin/env bash
                        myvar="hello"
                        myfunc() {
                        local x
                        local myvar="one two three"
                        for x in $myvar
                        do
                        echo $x
                        done
                        }
                        myfunc
                        echo $myvar $x
                        

此函數將輸出 "hello" -- 不重寫全局變量 "$myvar","$x" 在 myfunc 之外不繼續存在。在函數的第一行,我們創建了以后要使用的局部變量 x,而在第二個例子 (local myvar="one two three"") 中,我們創建了局部變量 myvar, 同時 為其賦值。在將循環控制變量定義為局部變量時,使用第一種形式很方便,因為不允許說:"for local x in $myvar"。此函數不影響任何全局變量,鼓勵您用這種方式設計所有的函數。只有在明確希望要修改全局變量時,才 應該使用 "local"。

posted on 2010-03-15 11:29 攀升 閱讀(298) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            91久久在线播放| 久久精品一区二区三区四区| 一本在线高清不卡dvd| 久久五月天婷婷| 欧美一二区视频| 国产美女精品免费电影| 亚洲一区二区在线播放| 日韩午夜一区| 欧美日韩精品免费观看视频完整| 亚洲美女中出| 亚洲日韩视频| 欧美va天堂| 亚洲精品孕妇| 亚洲丰满少妇videoshd| 美女性感视频久久久| 在线观看成人小视频| 免费不卡中文字幕视频| 久久天堂国产精品| 亚洲日韩欧美视频一区| 亚洲片区在线| 国产精品theporn| 先锋影音久久| 久久精品成人一区二区三区蜜臀| 中国日韩欧美久久久久久久久| 欧美日韩一视频区二区| 亚洲一区二区三区在线看 | 免费高清在线一区| 久久免费视频在线观看| 亚洲国产成人不卡| 亚洲毛片视频| 国产午夜精品全部视频播放| 美腿丝袜亚洲色图| 欧美日韩在线一二三| 久久久久青草大香线综合精品| 久久综合给合久久狠狠狠97色69| 中文网丁香综合网| 久久国产欧美| 一区二区三区国产精品| 欧美在线www| 日韩视频永久免费观看| 亚洲色无码播放| 在线看无码的免费网站| 亚洲精品国精品久久99热| 国产精品久久一区二区三区| 免费日韩av片| 国产精品视频第一区| 欧美大秀在线观看| 国产精品乱码人人做人人爱| 快射av在线播放一区| 欧美女人交a| 久久中文久久字幕| 欧美日韩一区二区三| 乱码第一页成人| 国产精品久久一区二区三区| 亚洲福利小视频| 狠狠色狠狠色综合日日tαg| 亚洲美女色禁图| 在线观看亚洲专区| 亚洲新中文字幕| 夜夜精品视频一区二区| 久久综合伊人77777蜜臀| 欧美中文在线观看| 国产精品porn| 亚洲精品资源美女情侣酒店| 亚洲第一精品电影| 欧美在线欧美在线| 欧美在线免费观看| 欧美视频一区二区三区| 亚洲二区精品| 亚洲东热激情| 久久成人综合视频| 欧美在线观看天堂一区二区三区| 欧美日韩国产综合一区二区| 亚洲国产岛国毛片在线| 亚洲福利在线视频| 久久久亚洲国产天美传媒修理工| 午夜精品亚洲| 国产精品久久二区| 亚洲午夜在线观看视频在线| 亚洲欧美国产视频| 国产精品久久毛片a| 亚洲一区精彩视频| 午夜伦欧美伦电影理论片| 欧美吻胸吃奶大尺度电影| 亚洲精选成人| 中文精品视频一区二区在线观看| 欧美精品一区二区三区很污很色的 | 一本色道久久综合亚洲精品不 | 一区二区三区免费观看| 欧美 亚欧 日韩视频在线| 免费av成人在线| 在线看国产日韩| 欧美凹凸一区二区三区视频| 欧美国产激情| 日韩网站在线看片你懂的| 欧美高清不卡| 亚洲青色在线| 亚洲综合二区| 国产一区二区福利| 久久中文久久字幕| 亚洲综合社区| 久久国产精品99国产| 91久久精品国产91久久性色tv | 久久久久亚洲综合| 国产欧美日韩在线视频| 香蕉久久一区二区不卡无毒影院| 午夜精品免费| 影音先锋久久资源网| 久热精品在线| 亚洲精华国产欧美| 亚洲一区二区三区四区中文 | 在线观看视频一区二区欧美日韩| 蜜臀久久99精品久久久画质超高清| 欧美黄色免费网站| 亚洲视频999| 国产欧美日韩高清| 免费久久99精品国产自在现线| 国产精品高清在线| 亚洲欧美在线一区| 国产一区二区在线免费观看| 久久夜色精品国产欧美乱极品| 亚洲第一狼人社区| 亚洲图片欧洲图片av| 国产老女人精品毛片久久| 久久精品一本久久99精品| 亚洲国产精品久久久久秋霞蜜臀| 亚洲特级片在线| 国内精品久久久久影院色| 欧美激情精品久久久久久| 亚洲摸下面视频| 亚洲福利视频一区| 久久不射中文字幕| 99精品热视频只有精品10| 国产色综合网| 欧美日韩免费高清一区色橹橹| 欧美一级日韩一级| 日韩视频在线观看国产| 久久久久久婷| 亚洲欧美精品一区| 亚洲精品视频在线| 韩国自拍一区| 国产精品你懂得| 欧美理论电影在线播放| 久久久久久久综合| 亚洲欧美日本日韩| 欧美成年网站| 亚洲国产欧美不卡在线观看| 国产精品综合久久久| 欧美精品日韩一区| 久久久久www| 亚洲欧美一区二区原创| 亚洲卡通欧美制服中文| 亚洲成人在线视频播放 | 日韩一级大片| 欧美激情精品| 久久亚洲午夜电影| 亚洲欧美日韩天堂| 一本色道久久综合精品竹菊 | 99国产精品视频免费观看| 欧美大尺度在线观看| 久久久精品日韩| 欧美一区二区三区喷汁尤物| 在线视频欧美日韩| 亚洲精品免费网站| 亚洲黄一区二区| 亚洲国产精品尤物yw在线观看| 一区二区在线视频| 狠狠色伊人亚洲综合成人| 国产亚洲激情在线| 国产亚洲欧美另类一区二区三区| 国产精品久久一级| 国产伦精品一区二区三区免费 | 国产一区二区精品| 国产精品一区二区三区乱码| 国产精品日韩在线播放| 国产精品激情电影| 国产精品日本| 国产日韩欧美综合一区| 国产欧美一区二区白浆黑人| 国产精品一香蕉国产线看观看| 国产精品久久久久久久9999| 国产精品扒开腿做爽爽爽视频| 欧美色图五月天| 国产精品午夜在线观看| 国产日韩欧美一区二区三区在线观看| 国产麻豆精品theporn| 国产乱码精品一区二区三区忘忧草 | 亚洲黄色成人| 99国产精品一区| 亚洲在线免费观看| 亚洲欧美视频在线观看| 欧美一区二区三区免费视| 久久激情久久| 欧美精品大片| 国产伦一区二区三区色一情| 在线观看亚洲精品视频| 99视频精品| 久久精品成人一区二区三区| 欧美成人激情在线| 亚洲深夜福利网站|