• <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>

            興海北路

            ---男兒仗劍自橫行
            <2008年4月>
            303112345
            6789101112
            13141516171819
            20212223242526
            27282930123
            45678910

            統計

            • 隨筆 - 85
            • 文章 - 0
            • 評論 - 17
            • 引用 - 0

            常用鏈接

            留言簿(6)

            隨筆分類

            隨筆檔案

            收藏夾

            全是知識啊

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            鳥哥學習Shell Scripts
            引用:
                學習Shell Scripts

                如果您真得很想要走信息這條路,并且想要好好的管理好屬于您的主機,那么,別說鳥哥不告訴您,Shell Scripts真的是必須要學習的一項課程!基本上,Shell scripts有點像是早期的批處理文件,亦即是將一些指令匯編起來一次執行,但是Shell scripts擁有更強大的功能,那就是,他可以進行類似程序(program)的撰寫,并且,不需要經過編譯(compiler)就能執行,真得很方便。加上,我們可透過shell script來簡化我們日常的工作管理,而且,整個Linux環境中,一些服務(services)的啟動都是透過shell script的,如果您對于script不了解,嘿嘿!發生問題時,可真是會求助無門的!所以,好好的學一學他吧!

            什么是Shell scripts?
                這個有趣的問題趕緊回答看看,什么是shell script呢?shell我們在認識bash當中已經提過了,那是一個文字接口底下讓我們與系統溝通的一個工具借口,那么script是啥?字面上的意義,script是[腳本、劇本]的意思。整句話是說,shell script是針對shell所寫的[劇本!] 什么東西啊?呵呵!其實,shell script是利用shell的功能所寫的一個[程序(program)],這個程序是使用純文字文件,將一些shell的語法與指令寫在里面,搭配正規表示法、管線命令與數據流重導向等功能,已達到我們所想要的處理目的。
                所以,簡單的說,shell script就像是早期DOS年代的批處理(.bat),最簡單的功能就是將許多指令匯整寫在一起,讓使用者很輕易的就能夠one touch(執行一個檔案“shell script”,就能夠一次執行多個指令),而,shell script 更提供數組、循環、條件與邏輯判斷等重要功能,讓使用者也可以直接以shell 來撰寫程序,而不必使用類似C程序語言等傳統程序撰寫的語法呢!
                那,這么說您可以了解了嗎?是的!shell script可以簡單的被看成是批處理,也可以被說成是一個程序語言,且這個程序語言由于都是利用shell與相關工具指令,所以不需要編譯即可執行,且擁有不錯的除錯(debug)工具,所以,他可以幫助系統管理員快速的管理好主機。

            ---------------------------------------------------------------------------------
            干嗎學習shell scripts?

                這是一個好問題,我又干嘛一定要學shell script?我又不是信息人,沒有寫程序的概念,那我干嗎還要學shell script呢?不要學可不可以啊?呵呵~如果Linux對您而言,您只是想要[會用]而已,那么,不需要學shell script也還無所謂,這部分先給他跳過去,等到有空的時候,再來好好的瞧一瞧。但是,如果您是真的想要玩清楚Linux的來龍去脈,那么shell script就不可不知,為什么呢?因為:

            自動化管理的重要依據:
                不用鳥哥說您也知道,管理一部主機真不是簡單的事情,每天要進行的任務就有:查詢登錄檔、追蹤流量、監控使用者使用主機狀態、主機各項硬件設備狀態、主機軟件更新查詢、更不要說得應付其它使用者的突然要求了。而這些工作,您想要自行手動處理,還是寫個簡單的程序來幫助您每日自動處理分析,若有問題才通知您呢?當然是讓系統自動工作比較好,對吧!呵呵~這就得要良好的shell script來幫忙的啦!

            追蹤與管理系統的重要工作:
                雖然我們還沒有提到服務啟動的方法,不過,這里可以先提一下,我們Linux系統的服務(services)啟動的接口,在/etc/init.d/這個目錄下,所有的檔案都是scriptsl;另外,包括開機(booting)過程也都是利用shell script來幫忙搜尋系統的相關設定數據,然后再代入各個服務的設定參數啊!舉例來說,如果我們想要重新啟動系統登錄文件,可以使用:[/etc/init.d/syslogd restart],那個syslogd檔案就是scripts啦!另外,我曾經在某一代的FC上面發現,啟動MySQL這個數據庫服務時,確實是可以啟動的,但是屏幕上卻老是出現[failure],后來才發現,原來啟動MySQL那個script會主動地以[空的密碼]去嘗試去登錄MySQL,但我修改過MySQL的密碼嘍~當然就登入失敗~后來改了改script,就略去這個問題啦!如此說來,script 確實是需要學習的啊!

            簡單入侵偵測功能:
                當我們的系統有異狀時,大多會將這些異狀記錄在系統記錄器,也就是我們提到的[系統登錄文件],那么我們可以在固定的幾分鐘內主動地去分析系統登錄文件,若察覺有問題,就立即通報管理員,或者是立刻加強防火墻的設定規則,如此一來,您的主機可就能夠達到[自我保護]的聰明學習功能啦~舉例來說,我們可以通過shell script 去分析[當該封包嘗試幾次還是聯機失敗后,就予以抵擋住該IP]之類的舉動,例如鳥哥寫過一個關于抵擋砍站軟件的shell script,就是用這個想法去達成的呢!

            連續指令單一化:
                其實,對于新手而言,script最簡單的功能就是:[匯整一些在command line 下達的連續指令,將他寫入scripts當中,而由直接執行scripts來啟動一連串的command line 指令輸出入!]例如:防火墻連續規則(iptables),開機加載程序的項目(就是在/etc/rc.d/rc.local里頭的數據),等等都是相似的功能啦!其實,說穿了,如果不考慮program的部分,那么scripts也可以想成,僅是幫我們把一大串的指令匯編在一個檔案里面,而直接執行該檔案就可以執行那一串又臭有長的指令段!就是這么簡單啦!

            簡易的數據處理:       
                由前一章 正規表示法的awk程序說明中,您可以發現,awk可以用來處理簡單的數據呢!例如薪資簡單的處理啊。shell script的功能更強大,例如鳥哥曾經用shell script直接處理數據的比對啊,文字數據得處理啊等等的,撰寫方便,速度又快(因為在Linux效能較佳),真的是很不錯用的啦!

            跨平臺支持與學習歷程較短:
                幾乎所有的Unix Like上面都可以跑shell script,連MS Windows系列也有相關的仿真器可以用,此外,shell script的語法是相當親和的,看都看得懂得文字,而不是機器碼,很容易學習~這些都是您可以加以考慮的學習點啊!

            上面這些都是您考慮學習shell script的特點~此外,shell script還可以簡單的以vi來直接編寫,實在是很方便的好東西!所以,還是建議您學習一下啦。

            不過,雖然shell script號稱是程序(program),但實際上,shell script處理數據的速度上是不太夠的。因為,shell script 用的是外部的指令與bash shell 的一些預設工具,所以,他常常會去呼叫外部的函數庫,因此,運算速度上面當然比不上傳統的程序語言。所以,shell script用在系統管理上面是很好的一項工具,但是用在處理大量數值運算上,就不夠好了,而且還很麻煩,因為:shell scripts 的速度較慢,且使用的CPU資源較多,造成主機資源的分配不良,還好,我們確實很少看到利用shell scripts在進行大量數據運算的,所以,不必擔心的啦!

            ----------------------------------------------------------------------------------------------------
            第一節 script的撰寫與執行

            如同前面講到的,shell script其實就是純文字文件(ASCII),我們可以編輯這個檔案,然后讓這個檔案來幫我們一次執行多個命令,或者是利用一些運算與邏輯判斷來幫我們達成某些功能。所以,要編輯這個檔案的內容時,當然就需要具備有bash shell 指令下達的相關知識。我們說過,要下達指令需要注意的事項在bash章節內已經提過,在shell script的撰寫同樣要用到這些注意事項的:
            如同前面bash command提到的,指令與參數間的多個空白會被忽略掉:
            而空白行也被忽略掉!并且[tab]也是不會被理會的!
            如果讀取到一個Enter符號(CR),就嘗試開始執行該行命令;
            至于如果一行的內容太多,則可以使用\[Enter]來延伸至下一行;
            此外,使用最多的#可做為批注!任何加在#后面的字,將全部被視為批注文字而被忽略!
            如此一來,我們在script內所撰寫的程序,就會被一行一行的執行,好了,那么這個程序假設文件名是shell.sh 好了,如何執行這個檔案呢?很簡單,可以由底下幾個方法:
            將shell.sh加上可讀與執行(rx)的權限,然后就能夠以./shell.sh來執行了;
            直接以sh shell.sh的方式來直接執行即可。
            反正重點就是要讓那個shell.sh內的指令可以被執行的意思!那我為何需要使用./shell.sh來下達指令?還記得我們在bash 里面一直強調的,指令是否能夠被執行與PATH這個環境變量有關,所以,要執行[目前這個目錄下的某個檔案]就需要加上 ./這個目錄!另外,其實您也可以將shell.sh放在您的家目錄下的~/bin這個目錄中,然后利用PATH="$PATH"~/bin的設定,就能夠直接執行您的script了
                  那,為何sh shell.sh也可以執行呢?這是因為/bin/sh其實就是/bin/bash,使用sh shell.sh亦即告訴系統,我想要直接以bash的功能來執行shell.sh這個檔案內的相關指令的意思。而我們也可以利用sh的參數,如 -n 及 -x來檢查與追蹤shell.sh的語法是否正確!

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

            撰寫第一個script
            不論是那個門派,要學武功要從掃地做起,那么要學程序呢?呵呵,肯定是由[秀出Hello World!]這個字眼開始的!OK!那么鳥哥就先寫一個script給大家瞧一瞧:
            [root@linux~]# mkdir scripts; cd scripts
            [root@linux scripts]# vi sh01.sh
            #!/bin/bash
            # Program:
            #            This program is used to show "Hello World!" in screen.
            # History:
            # 2005/08/23 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH
            echo -e "Hello World!\a\n"
            exit 0


            在我們這個章節當中,請將所有的撰寫的script放置到您家目錄的~/scripts這個目錄內,比較好管理啦!上面的寫法當中,我主要將整個程序的撰寫分成數段,大致是這樣:
            第一行 #!/bin/bash在宣告這個script使用的shell 名稱:
            因為我們使用的是bash,所以,必須要以[#!/bin/bash]來宣告這個檔案內的語法使用bash的語法!那么當這個程序被執行時,他就能夠加載bash的相關環境設定檔,并且執行bash來使我們底下的指令能夠執行!這很重要的!(在很多狀況中,如果沒有設定好這一行,那么該程序很可能會無法執行,因為系統可能無法判斷該程序需要使用什么shell來執行!)

            程序內容的宣告:
                  整個script當中,除了第一行的#!是用來宣告shell的之外,其他的#就是[批注]用途!所以上面的程序當中,第二行以下就是用來說明整個程序的狀態。一般來說,建議您一定要養成說明該script的:1.內容與功能;2.版本信息;3.作者與聯絡方式;4.建檔日期;5.歷史紀錄等等。這將有助于未來程序的改寫與debug!

            主要環境變量的宣告:
                  建議務必要將一些重要的環境變量設定好,鳥哥個人認為,PATH是當中最重要的!如此一來,則可讓我們這支程序在進行時,可以直接下達指令,而不必寫絕對路徑!比較好!

            主要程序部分
                  就將主要的程序寫好即可!在這個例子當中,就是echo那一行。

            執行成果告知
                  是否記得我們在bash里面要討論一個指令的執行成功與否,可以使用$?這個變量來觀察~那么我們就也可以利用exit這個指令來讓程序中斷,并且回傳一個數值給系統,在我們這個例子當中,我使用exit 0,這代表離開script,并且回傳一個0給系統,所以我執行完這個script后,若接著下達echo $?則可以得到0的值!更聰明的讀者應該也知道了,呵呵!利用這個exit n的功能,我們還可以自訂錯誤訊息,讓這支程序變得更加的smart呢!
            接下來執行看看結果是怎樣的?
            [root@linux scripts]# sh sh01.sh
            Hello World!


            您會看到屏幕是這樣,而且應該還會聽到[咚]的一聲,為什么呢?還記得前一章提到的printf吧?用echo接著那些特殊的按鍵也可以發生同樣的事情~不過,echo必須要加上 -e 的參數才行,呵呵,在您寫完這個小script之后,您就可以大聲地說:[我也會寫程序了]!

            另外,你也可以利用:[chmod a+x sh01.sh; ./sh01.sh] 來執行這個script呢!

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

            --------------------------------------------------------------------------------
            撰寫 shell script 的良好習慣建立

            一個良好習慣的養成是很重要的~大家在剛開始撰寫程序的時候,最容易忽略這部分, 認為程序寫出來就好了,其它的不重要。其實,如果程序的說明能夠更清楚, 那么對您自己是有很大的幫助的。

            舉例來說,鳥哥自己為了自己的需求,曾經撰寫了不少的 script 來幫我進行主機 IP 的偵測啊、 登錄檔分析與管理啊、自動上傳下載重要 設定檔啊等等的,不過,早期就是因為太懶了, 管理的主機又太多了,常常同一個程序在不同的主機上面進行更改,到最后,到底哪一支才是最新的都記不起來,  而且,重點是,我到底是改了哪里??為什么做那樣的修改?都忘的一干二凈~真要命~

            所以,后來鳥哥在寫程序的時候,通常會比較仔細的將程序的設計過程給他記錄下來, 而且還會記錄一些歷史紀錄,如此一來,好多了~ 至少很容易知道我修改了哪些數據,以及程序修改的理念與邏輯概念等等, 在維護上面是輕松很多很多的喔!

            另外,在一些環境的設定上面,畢竟每個人的環境都不相同,為了取得較佳的執行環境, 我都會自行先定義好一些一定會被用到的環境變量,例如  PATH 這個玩意兒! 這樣比較好啦~所以說,建議您一定要養成良好的 script 撰寫習慣, 在每個 script 的文件頭處記錄好:
            script 
            的功能; 
            script 
            的版本信息; 
            script 
            的作者與聯絡方式; 
            script 
            的版權宣告方式; 
            script 
             History (歷史紀錄) 
            script 
            內較特殊的指令,使用絕對路徑的方式來下達; 
            script 
            運作時需要的環境變量預先宣告與設定。

            --------------------------------------------------------------------------------
            簡單的 shell script 練習

            在第一支 shell script 撰寫完畢之后,相信您應該具有基本的撰寫功力了。 接下來,在開始更深入的程序概念之前,我們先來玩一些比 較有趣的簡單的小范例好了。 底下的范例中,達成結果的方式相當的多,建議您先自行撰寫看看,寫完之后再與鳥哥寫的內容比對, 這樣才能更加深概念喔! 好!不啰唆,我們就一個一個來玩吧!


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

            變量內容由使用者決定 
            很多時候我們需要使用者輸入一些內容,好讓程序可以順利運作。 簡單的來說,大家應該都有安裝過軟件的經驗,安裝的時候,他不是會問您『要安裝到那個目錄去?』嗎? 那個讓使用者輸入的數據的動作,就是讓使用者輸入變量內容啦。

            你應該還記得在 bash 的時候,我們有學到一個 read 指令吧?忘記的話,請自行回頭去閱讀一番。 現在,請你以 read 指令的用 途,撰寫一個 script ,他可以讓使用者輸入:1 first name  2. last name 最后并且在屏幕上顯示: Your full name is: 』的內容:
            [root@linux scripts]# vi sh02.sh
            #!/bin/bash
            # Program:
            #  Let user keyin their first and last name, and show their full name.
            # History:
            2005/08/23 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            read -p "Please input your first name: " firstname
            read -p "Please input your last name:  " lastname
            echo -e "\nYour full name is: $firstname $lastname"

             
            將上面這個 sh02.sh 執行一下,你就能夠發現使用者自己輸入的變量可以被取用的哩! 很不錯吧!加油!



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

            利用 date 進行檔案的建立 
            想象一個狀況,如果我每天要進行備份,而備份的數據又不想被覆蓋掉,也就是說, 我想要將每天備份的數據放在不同的檔案中。哇!這真困擾啊?難道 要我每天去修改 script  不需要啊!因為每天的『日期』并不相同,所以我可以將檔名取成類似: backup.20050802  不就可以 每天一個不同檔名了嗎?呵呵!確實如此。好了,接下來出個例子: 我想要建立三個空的檔案,檔名最開頭由使用者輸入決定,假設使用者輸入  filename 好了, 那今天的日期是 2005/08/23 ,我想要以前天、昨天、今天的日期來建立這個檔案,亦即  filename_20050821, filename_20050822, filename_20050823 ,該如何是好?
            [root@linux scripts]# vi sh03.sh
            #!/bin/bash
            # Program:
            #  User can keyin filename to touch 3 new files.
            # History:
            2005/08/23 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            # 1. 
            讓使用者輸入文件名稱,并取得 fileuser 這個變量;
            echo -e "I will use 'touch' command to create 3 files."
            read -p "Please input the filename what you want: " fileuser

            # 2. 
            為了避免使用者隨意按 Enter ,利用變量功能分析文件名是否有設定?
            filename=${fileuser:-"filename"}

            # 3. 
            開始利用 date 指令來取得所需要的檔名了;
            date1=`date --date='2 days ago' +%Y%m%d`
            date2=`date --date='1 days ago' +%Y%m%d`
            date3=`date +%Y%m%d`
            file1="$filename""$date1"
            file2="$filename""$date2"
            file3="$filename""$date3"

            # 4. 
            將檔名建立吧!
            touch $file1
            touch $file2
            touch $file3

             
            我透過一些簡單的動作,這些動作都可以在 bash 那一章里面找到, 包括小指令 (`) 的取得訊息、變量的設定功能、變量的累加以及利用  touch 指令輔助! 如果您開始執行這個 sh03.sh 之后,你可以進行兩次輸入,一次直接按 [Enter] 來查閱檔名是啥? 一次可以輸 入一些字符,這樣來判斷你的檔案喔!關于 date 的指令應用,請 man date 吧! ^_^



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

            數值運算的方法 
            各位看官應該還記得,我們可以使用 declare 來定義變量的類型吧?! 這樣才能夠進行加減運算啊!可惜的是, bash shell  頭預設僅支持到整數的數據。 OK!那我們來玩玩看,如果我們要使用者輸入兩個變量,然后將兩個變量的內容相乘, 最后輸出相乘的結果,那可以怎么做?
            [root@linux scripts]# vi sh04.sh
            #!/bin/bash
            # Program:
            #  User can input 2 integer to cross by!
            # History:
            2005/08/23 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH
            echo -e "You SHOULD input 2 number, I will cross they! \n"
            read -p "first number:  " firstnu
            read -p "second number: " secnu
            total=$(($firstnu*$secnu))
            echo -e "\nThe number $firstnu x $secnu is ==> $total"

             
            在數字的運算上,我們可以使用『 declare -i total=$firstnu*$secnu  也可以使用上面的方式來進行!基本上,鳥哥比較建議使用這樣的方式來進行運算: 
            var=$((
            運算內容))
            不但容易記憶,而且也比較方便的多~未來您可以使用這種方式來計算的呀!至于數值運算上的處理, 則有:+, -, *, /, %等等。 那個 % 是取余數啦~舉例來說, 13  3 取余數,結果是 13=4*3+1,所以余數是 1 啊!就是:
            [root@linux scripts]# nu=$((13%3)); echo $nu
            1

             
            這樣了解了吧?!多多學習與應用喔! ^_^


            --------------------------------------------------------------------------------
            善用判斷式

             bash 章節中,我們提到過 $? 這個變量所代表的意義, 此外,也透過 &&  || 來作為前一個指令是否能夠成 功進行的一個參考。 那么,如果我想要知道 /dmtsai 這個目錄是否存在時,難道一定要使用 ls 來執行, 然后再以 $? 來判斷執行成果嗎? 呵呵!當然不需要! 我們可以透過『 test 』這個指令來偵測呢!


            --------------------------------------------------------------------------------
            利用 test 指令的測試功能

            當我要檢測系統上面某些檔案或者是相關的屬性時,利用 test 這個指令來工作, 真是好用得不得了,舉例來說,我要檢查 /dmtsai 是否存在時,使用:
            [root@linux ~]# test -e /dmtsai

             
            執行結果并不會顯示任何訊息,但最后我們可以透過 $?  &&  || 來展現整個結果呢! 例如我們在將上面的例子改寫成這樣:
            [root@linux ~]# test -e /dmtsai && echo "exist" || echo "Not exist"

             
            最終的結果可以告知我們是『exist』還是『Not exist』呢!那我知道 -e 是測試一個『東西』在不在, 如果還想要測試一下該檔名是啥玩意兒時,還有哪些標志可以來判斷的呢?呵呵!有底下這些東西喔!

            測試的標志 代表意義 
            1. 
            關于某個檔名的『類型』偵測(存在與否),如 test -e filename 
            -e 
            該『檔名』是否存在?(常用
            -f 
            該『檔名』是否為檔案(file)(常用
            -d 
            該『文件名』是否為目錄(directory)(常用
            -b 
            該『檔名』是否為一個 block device 裝置? 
            -c 
            該『檔名』是否為一個 character device 裝置? 
            -S 
            該『檔名』是否為一個 Socket 檔案? 
            -p 
            該『檔名』是否為一個 FIFO (pipe) 檔案? 
            -L 
            該『檔名』是否為一個連結檔? 
            2. 
            關于檔案的權限偵測,如 test -r filename 
            -r 
            偵測該檔名是否具有『可讀』的屬性? 
            -w 
            偵測該檔名是否具有『可寫』的屬性? 
            -x 
            偵測該檔名是否具有『可執行』的屬性? 
            -u 
            偵測該文件名是否具有『SUID』的屬性? 
            -g 
            偵測該文件名是否具有『SGID』的屬性? 
            -k 
            偵測該文件名是否具有『Sticky bit』的屬性? 
            -s 
            偵測該檔名是否為『非空白檔案』? 
            3. 
            兩個檔案之間的比較,如: test file1 -nt file2 
            -nt (newer than)
            判斷 file1 是否比 file2  
            -ot (older than)
            判斷 file1 是否比 file2  
            -ef 
            判斷 file2  file2 是否為同一檔案,可用在判斷 hard link 的判定上。 主要意義在判定,兩個檔案是否均指向同一個 inode 哩! 
            4. 
            關于兩個整數之間的判定,例如 test n1 -eq n2 
            -eq 
            兩數值相等 (equal) 
            -ne 
            兩數值不等 (not equal) 
            -gt n1 
            大于 n2 (greater than) 
            -lt n1 
            小于 n2 (less than) 
            -ge n1 
            大于等于 n2 (greater than or equal) 
            -le n1 
            小于等于 n2 (less than or equal) 
            5. 
            判定字符串的數據 
            test -z string 
            判定字符串是否為 0 ?若 string 為空字符串,則為 true 
            test -n string 
            判定字符串是否非為 0 ?若 string 為空字符串,則為 false
            注: -n 亦可省略 
            test str1 = str2 
            判定 str1 是否等于 str2 ,若相等,則回傳 true 
            test str1 != str2 
            判定 str1 是否不等于 str2 ,若相等,則回傳 false 
            6. 
            多重條件判定,例如: test -r filename -a -x filename 
            -a (and)
            兩狀況同時成立!例如 test -r file -a -x file,則 file 同時具有 r  x 權限時,才回傳 true 
            -o (or)
            兩狀況任何一個成立!例如 test -r file -o -x file,則 file 具有 r  x 權限時,就可回傳 true 
            反相狀態,如 test ! -x file ,當 file 不具有 x 時,回傳 true 

            OK
            !現在我們就利用 test 來幫我們寫幾個簡單的例子。首先,判斷一下, 讓使用者輸入一個檔名,我們判斷:
            這個檔案是否存在,若不存在則給予一個『Filename does not exist』的訊息,并中斷程序; 
            若這個檔案存在,則判斷他是個檔案或目錄,結果輸出『Filename is regular file』或 Filename is directory 
            判斷一下,執行者的身份對這個檔案或目錄所擁有的權限,并輸出權限數據!
            你可以先自行創作看看,然后再跟底下的結果討論討論。注意利用 test  && 還有 || 等標志!
            [root@linux scripts]# vi sh05.sh
            #!/bin/bash
            # Program:
            #  Let user input a filename, the program will search the filename
            # 1.) exist? 2.) file/directory? 3.) file permissions 
            # History:
            2005/08/25 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            # 1. 
            讓使用者輸入檔名,并且判斷使用者是否真的有輸入字符串?
            echo -e "The program will show you that filename is exist which input by you.\n\n"
            read -p "Input a filename : " filename
            test -z $filename && echo "You MUST input a filename." && exit 0
            # 2. 
            判斷檔案是否存在?
            test ! -e $filename && echo "The filename $filename DO NOT exist" && exit 0
            # 3. 
            開始判斷檔案類型與屬性
            test -f $filename && filetype="regulare file"
            test -d $filename && filetype="directory"
            test -r $filename && perm="readable"
            test -w $filename && perm="$perm writable"
            test -x $filename && perm="$perm executable"
            # 4. 
            開始輸出信息!
            echo "The filename: $filename is a $filetype"
            echo "And the permission are : $perm"

             
            很有趣的例子吧!您可以自行再以其它的案例來撰寫一下可用的功能呢!



            --------------------------------------------------------------------------------
            利用判斷符號 [ ]

            除了我們很喜歡使用的 test 之外,其實,我們還可以利用判斷符號『 [ ] 』來進行數據的判斷呢! 舉例來說,如果我想要知道 $HOME 這個變量是否為空的,可以這樣做:
            [root@linux ~]# [ -z "$HOME" ]

             
            但使用 [] 要特別注意的是,在上述的每個組件中間都需要有空格鍵來分隔,假設我空格鍵使用『□』來表示, 那么,在這些地方你都需要有空格鍵:
            [  "$HOME"  ==  "$MAIL"  ]
            [
            "$HOME"=="$MAIL"]
             
                            

             
            上面的例子在說明,兩個字符串 $HOME  $MAIL 是否相同的意思,相當于 test $HOME = $MAIL 的意思啦! 而如 果沒有空白分隔,例如 [$HOME==$MAIL] 時,我們的 bash 就會顯示錯誤訊息了!這可要很注意啊! 所以說,您最好要注意:
            在中括號 [] 內的每個組件都需要有空格鍵來分隔; 
            在中括號內的變量,最好都以雙引號來設定; 
            在中括號內的常數,最好都以單或雙引號來設定。
            舉例來說,假如我設定了 name="VBird Tsai" ,然后這樣判定:
            [root@linux ~]# name="VBird Tsai"
            [root@linux ~]# [ $name == "VBird" ]
            bash: [: too many arguments

             
            為什么呢?因為 $name 如果沒有使用雙引號刮起來,那么上面的判定式會變成: 
            [ VBird Tsai == "VBird" ] 
            而不是我們要的: 
            [ "VBird Tsai" == "VBird" ] 
            這可是差很多的喔!另外,中括號的使用方法與標志與 test 幾乎一模一樣啊~ 只是中括號比較常用在條件判斷式 if ..... then ..... fi 的情況中就是了。 好,那我們也繼續來做一個小案例好了:
            當執行一個程序的時候,這個程序會讓使用者選擇 Y  N  
            如果使用者輸入 Y  y 時,就顯示『 OK, continue  
            如果使用者輸入 n  N 時,就顯示『 Oh, interrupt !』 
            如果不是 Y/y/N/n 之內的其它字符,就顯示『I don't know what is your choise
            利用中括號、 &&  || 來繼續吧!
            [root@linux scripts]# vi sh06.sh
            #!/bin/bash
            # Program:
            #  This program will show the user's choice
            # History:
            2005/08/25 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            read -p "Please input (Y/N): " yn
            [ "$yn" == "Y" -o "$yn" == "y" ] && echo "OK, continue" && exit 0
            [ "$yn" == "N" -o "$yn" == "n" ] && echo "Oh, interrupt!" && exit 0
            echo "I don't know what is your choise" && exit 0

             
            很有趣吧!利用這個字符串判別的方法,我們就可以很輕松的將使用者想要進行的工作分門別類呢! 接下來,我們再來談一些其它有的沒有的東西吧!

            Tips:
            為什么判斷式里面下達等于要用 == 而不是一個 = 就好了呢?我們在前一章正規表示法里面的 awk 提到, 只有一個 = 用來給予一個變量設定其內容,邏輯判斷時,則會給予兩個等于, 亦即『比較』而非『設定』的意思~這里要好好的分辨一下喔! ^_^   


            --------------------------------------------------------------------------------
            Shell script 
            的預設變數($0, $1...)

            其實,當我們執行一個 shell script 時,在這個 shell script 里面就已將幫我們做好一些可用的變量了。 舉例來說,在不久的將來,您就會發現,當我們要啟動一個系統服務時,可能會下達類似這樣的指令:
            [root@linux ~]# /etc/init.d/crond restart

             
            那是啥玩意兒?呵呵!就是『向 /etc/init.d/crond 這個 script 下達 restart 的指令』, 咦!我們不是都使  read 來讀取使用者輸入的變量內容嗎?為啥我可以直接在 script 后面接上這個參數? 這是因為 shell script 幫我們設定好 一些指定的變量了!變量的對應是這樣的:

            /path/to/scriptname  opt1  opt2  opt3  opt4  ...
                   $0             $1    $2    $3    $4   ...

             
            這樣夠清楚了吧?!執行的文件名為 $0 這個變量,第一個接的參數就是 $1 啊~ 所以,只要我們在 script 里面善用 $1 的話, 就可以很簡單的立即下達某些指令功能了! 好了,來做個例子吧~假設我要執行一個 script ,執行后,該 script 會自動列出自己的檔名,  還有后面接的前三個參數,該如何是好?
            [root@linux scripts]# vi sh07.sh
            #!/bin/bash
            # Program:
            #  The program will show it's name and first 3 parameters.
            # History:
            2005/08/25 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            echo "The script naem is ==> $0"
            [ -n "$1" ] && echo "The 1st paramter is ==> $1" || exit 0
            [ -n "$2" ] && echo "The 2nd paramter is ==> $2" || exit 0
            [ -n "$3" ] && echo "The 3th paramter is ==> $3" || exit 0

             
            這支程序里面鳥哥加上了一些控制式,亦即利用 &&  || 來加以判斷 $1 ~ $3 是否存在? 若存在才顯示,若不存在就中斷~執行結果如下:
            [root@linux scripts]# sh sh07.sh theone haha quot
            The script naem is ==> sh07.sh
            The 1st paramter is ==> theone
            The 2nd paramter is ==> haha
            The 3th paramter is ==> quot

             
            上面這七的例子都很簡單吧?幾乎都是利用 bash 的相關功能而已~ 不難啦~底下我們就要使用條件判斷式來進行一些分別功能的設定了,好好瞧一瞧先~ 

            --------------------------------------------------------------------------------
            條件判斷式:

            只要講到『程序』的話,那么條件判斷式,亦即是『 if then 』這種判別式肯定一定要學習的! 因為很多時候,我們都必須要依據某些數據來 判斷程序該如何進行。舉例來說,我們在上頭不是有練習當使用者輸入 Y/N 時,必須要執行不同的訊息輸出嗎?簡單的方式可以利用 &&   || ,但如果我還想要執行一堆指令呢? 那真的得要 if then 來幫忙啰~底下我們就來聊一聊!


            --------------------------------------------------------------------------------
            利用 if .... then

            這個 if .... then 是最常見的條件判斷式了~簡單的說,就是當符合某個條件判斷的時候, 就予以進行某項工作就是了。我們可以簡單的這樣看:
            if [ 
            條件判斷式 ]; then
            當條件判斷式成立時,可以進行的指令工作內容;
            fi

             
            至于條件判斷式的判斷方法,與前一小節的介紹相同啊!較特別的是,如果我有多個條件要判別時, 除了 sh06.sh 那個案例,也就是將多個條 件寫入一個中括號內的情況之外, 我還可以有多個中括號來隔開喔!而括號與括號之間,則以 &&  || 來隔開,他們的意義是: 
            && 
            代表 AND  
            || 
            代表 or 
            所以,在使用中括號的判斷式中, &&  || 就與指令下達的狀態不同了。舉例來說, sh06.sh 那個例子我可以改寫成這樣:
            [root@linux scripts]# vi sh06-2.sh
            #!/bin/bash
            # Program:
            #  This program will show the user's choice
            # History:
            2005/08/25 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            read -p "Please input (Y/N): " yn

            if [ "$yn" == "Y" ] || [ "$yn" == "y" ]; then
            echo "OK, continue"
            exit 0
            fi
            if [ "$yn" == "N" ] || [ "$yn" == "n" ]; then
            echo "Oh, interrupt!"
            exit 0
            fi
            echo "I don't know what is your choise" && exit 0

             
            不過,由這個例子看起來,似乎也沒有什么了不起吧? sh06.sh 還比較簡單呢~ 但是,如果我們考慮底下的狀態,您就會知道 if then 的好處了:
            if [ 
            條件判斷式 ]; then
            當條件判斷式成立時,可以進行的指令工作內容;
            else
            當條件判斷式不成立時,可以進行的指令工作內容;
            fi

             
            如果考慮更復雜的情況,則可以使用這個語法:
            if [ 
            條件判斷式一 ]; then
            當條件判斷式一成立時,可以進行的指令工作內容;
            elif [ 
            條件判斷式二 ]; then
            當條件判斷式二成立時,可以進行的指令工作內容;
            else
            當條件判斷式一與二均不成立時,可以進行的指令工作內容;
            fi

             
            那我就可以將 sh06-2.sh 改寫成這樣:
            [root@linux scripts]# vi sh06-3.sh
            #!/bin/bash
            # Program:
            #  This program will show the user's choice
            # History:
            2005/08/25 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            read -p "Please input (Y/N): " yn

            if [ "$yn" == "Y" ] || [ "$yn" == "y" ]; then
            echo "OK, continue"
            elif [ "$yn" == "N" ] || [ "$yn" == "n" ]; then
            echo "Oh, interrupt!"
            else
            echo "I don't know what is your choise"
            fi

             
            是否程序變得很簡單,而且依序判斷,可以避免掉重復判斷的狀況,這樣真的很容易設計程序的啦! ^_^ 好了,那么如果我要偵測你所輸入的參數是 否為 hello   也就是說,如果我想要知道,你在程序后面所接的第一個參數 (就是 $1 啊!是否為 hello 
            如果是的話,就顯示 "Hello, how are you ?" 
            如果沒有加任何參數,就提示使用者必須要使用的參數下達法; 
            而如果加入的參數不是 hello ,就提醒使用者僅能使用 hello 為參數。
            整個程序的撰寫可以是這樣的:
            [root@linux scripts]# vi sh08.sh
            #!/bin/bash
            # Program:
            #  Show "Hello" from $1....
            # History:
            2005/08/28 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            if [ "$1" == "hello" ]; then
            echo "Hello, how are you ?"
            elif [ "$1" == "" ]; then
            echo "You MUST input parameters, ex> $0 someword"
            else
            echo "The only parameter is 'hello'"
            fi

             
            然后您可以執行這支程序,分別在 $1 的位置輸入 hello, 沒有輸入與隨意輸入, 就可以看到不同的輸出啰~是否還覺得挺簡單的啊!  ^_^。事實上, 學到這里,也真的很厲害了~好了,底下我們繼續來玩一些比較大一點的啰~ 我們在前一章已經學會了 grep 這個好用的玩意兒,那 么多學一個叫做 netstat 的指令, 這個指令可以查詢到目前主機有開啟的網絡服務端口口 (service ports) 相關的功能我們會在 服務器架設篇繼續介紹,這里您只要知道,我可以利用『 netstat -tuln 』來取得目前主機有啟動的服務, 而且取得的信息有點像這樣:
            [root@linux ~]# netstat -tuln
            Active Internet connections (only servers)
            Proto Recv-Q Send-Q Local Address   Foreign Address    State
            tcp        0      0 0.0.0.0:199     0.0.0.0:*          LISTEN
            tcp        0      0 :::80           :::*               LISTEN
            tcp        0      0 :::22           :::*               LISTEN
            tcp        0      0 :::25           :::*               LISTEN

             
            上面的重點是特殊字體的那個部分,那些特殊字體的部分代表的就是 port 啰~ 那么每個 port 代表的意義為何呢?幾個常見的 port 與相關網絡服務的關系是: 
            80: WWW 
            22: ssh 
            21: ftp 
            25: mail
            那我如何透過 netstat 去偵測我的主機是否有開啟這四個主要的網絡服務端口口呢? 我可以簡單的這樣去寫這個程序喔:
            [root@linux scripts]# vi sh09.sh
            #!/bin/bash
            # Program:
            #  Using netstat and grep to detect WWW,SSH,FTP and Mail services.
            # History:
            2005/08/28 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            # 1. 
            先作一些告知的動作而已~
            echo "Now, the services of your Linux system will be detect!"
            echo -e "The www, ftp, ssh, and mail will be detect! \n"

            # 2. 
            開始進行一些測試的工作,并且也輸出一些信息啰!
            testing=`netstat -tuln | grep ":80 "`
            if [ "$testing" != "" ]; then
            echo "WWW is running in your system."
            fi
            testing=`netstat -tuln | grep ":22 "`
            if [ "$testing" != "" ]; then
            echo "SSH is running in your system."
            fi
            testing=`netstat -tuln | grep ":21 "`
            if [ "$testing" != "" ]; then
            echo "FTP is running in your system."
            fi
            testing=`netstat -tuln | grep ":25 "`
            if [ "$testing" != "" ]; then
            echo "Mail is running in your system."
            fi

             
            這樣又能夠一個一個的檢查啰~是否很有趣啊! ^_^。接下來,我們再來玩更難一點的。 我們知道可以利用 date 來顯示日期與時間,也可以 利用 $((計算式)) 來計算數值運算。 另外, date 也可以用來顯示自 19710101 以來的『總秒數』 (請自行查閱  man date  info date) 。那么,您是否可以撰寫一支小程序,用來『計算退伍日期還剩幾天?』也就是說:
            先讓使用者輸入他們的退伍日期; 
            再由現在日期比對退伍日期; 
            由兩個日期的比較來顯示『還需要幾天』才能夠退伍的字樣。
            似乎挺難的樣子?其實也不會啦,利用『 date --date="YYYYMMDD" +%s 』就能夠達到我們所想要的啰~如果您已經寫完了程序,對照底下的寫法試看看:
            [root@linux scripts]# vi sh10.sh
            #!/bin/bash
            # Program:
            #  Tring to calculate your demobilization date at how many days 
            # later...
            # History:
            2005/08/29 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            # 1. 
            告知使用者這支程序的用途,并且告知應該如何輸入日期格式?
            echo "This program will try to calculate :"
            echo "How many days about your demobilization date..."
            read -p "Please input your demobilization date (YYYYMMDD ex>20050401): " date2

            # 2. 
            測試一下,這個輸入的內容是否正確?利用正規表示法啰~
            date_d=`echo $date2 |grep '[0-9]\{8\}'`
            if [ "$date_d" == "" ]; then
            echo "You input the wrong format of date...."
            exit 1
            fi

            # 3. 
            開始計算日期啰~
            declare -i date_dem=`date --date="$date2" +%s`
            declare -i date_now=`date +%s`
            declare -i date_total_s=$(($date_dem-$date_now))
            declare -i date_d=$(($date_total_s/60/60/24))
            if [ "$date_total_s" -lt "0" ]; then
            echo "You had been demobilization before: " $((-1*$date_d)) " ago"
            else
            declare -i date_h=$(($(($date_total_s-$date_d*60*60*24))/60/60))
            echo "You will be demobilized after $date_d days and $date_h hours."
            fi

             
            瞧一瞧,這支程序可以幫您計算退伍日期呢~如果是已經退伍的朋友, 還可以知道已經退伍多久了~哈哈!很可愛吧~利用 date 算出自  1971/01/01 以來的總秒數, 再與目前的總秒數來比對,然后以一天的總秒數 (60*60*24) 為基數去計算總日數, 就能夠得知兩者的 差異了~瞧~全部的動作都沒有超出我們所學的范圍吧~ ^_^ 還能夠避免使用者輸入錯誤的數字,所以多了一個正規表示法的判斷式呢~ 這個例子比較難, 有興趣想要一探究竟的朋友,可以作一下課后練習題 關于計算生日的那一題喔!~加油!



            --------------------------------------------------------------------------------
            利用 case ..... esac 判斷

            上個小節提到的『 if .... then .... fi 』對于變量的判斷中, 是以比對的方式來分辨的,如果符合狀態就進行某些行為,并 且透過較多層次 ( 就是 elif ... ) 的方式來進行多個變量的程序代碼撰寫,譬如 sh08.sh 那個小程序,就是用這樣的方式來的啰。  好,那么萬一我有多個既定的變量內容,例如 sh08.sh 當中,我所需要的變量就是 "hello" 及空字符串兩個, 那么我只要針對這兩個變量來 設定狀況就好了對吧?!那么可以使用什么方式來設計呢? 呵呵~就用 case ... in .... esac 吧~,他的語法如下:
            case $
            變量名稱 in
              "
            第一個變量內容")
            程序段
            ;;
              "
            第二個變量內容")
            程序段
            ;;
              *)
            不包含第一個變量內容與第二個變量內容的其它程序執行段
            exit 1
            ;;
            esac

             
            要注意的是,這個語法是以 case 為開頭,而以 esac 為結尾,啥?為何是 esac 呢?想一想,既然 if 的結尾是 fi ,那么  case 的結尾當然就是將 case 倒著寫,自然就是 esac 啰~ ^_^,很好記吧~ 另外,每一個變量內容的程序段最后都需要兩個分號  (;;) 來代表該程序段落的結束,這挺重要的喔! 至于為何需要有 * 這個變量內容在最后呢?這是因為,如果使用者不是輸入變量內容一或二時, 我們 可以告知使用者相關的信息啊!舉例來說,我們如果將 sh08.sh 改寫的話, 他應該會變成這樣喔!
            [root@linux scripts]# vi sh08-2.sh
            #!/bin/bash
            # Program:
            #  Show "Hello" from $1.... by using case .... esac
            # History:
            2005/08/29 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            case $1 in
              "hello")
            echo "Hello, how are you ?"
            ;;
              "")
            echo "You MUST input parameters, ex> $0 someword"
            ;;
              *)
            echo "Usage $0 {hello}"
            ;;
            esac

             
            在上面這個 sh08-2.sh 的案例當中,如果你輸入『 sh sh08-2.sh test 』來執行, 那么屏幕上就會出現 Usage sh08-2.sh {hello}』的字樣,告知執行者僅能夠使用 hello 喔~ 這樣的方式對于需要某些固定字符串來執行的變量內 容就顯的更加的方便呢? 這種方式您真的要熟悉喔!這是因為系統的很多服務的啟動 scripts 都是使用這種寫法的, 舉例來說,我們 Linux  的服務啟動放置目錄是在 /etc/init.d/ 當中,我已經知道里頭有個 syslog 的服務,我想要重新啟動這個服務,可以這樣做: 
            /etc/init.d/syslog restart
            重點是那個 restart 啦~如果您進入 /etc/init.d/syslog 就會看到他使用的是 case 語法, 并且會規定某些既 定的變量內容,你可以直接下達 /etc/init.d/syslog   script 就會告知你有哪些后續接的變量可以使用啰~方便吧!  ^_^

            一般來說,使用『 case $變量 in 』這個語法中,當中的那個 $變量 大致有兩種取得的方式:
            直接下達式:例如上面提到的,利用『 script.sh variable  的方式來直接給予 $1 這個變量的內容,這也是在 /etc/init.d 目錄下大多數程序的設計方式。 
            交互式:透過 read 這個指令來讓使用者輸入變量的內容。
            這么說或許您的感受性還不高,好,我們直接寫個程序來玩玩:讓使用者能夠輸入 one, two, three  并且將使用者的變量顯示到屏幕上,如果不是 one, two, three 時,就告知使用者僅有這三種選擇。
            [root@linux scripts]# vi sh11.sh
            #!/bin/bash
            # Program:
            #  Let user input one, two, three and show in screen.
            # History:
            2005/08/29 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            echo "This program will print your selection !"
            # read -p "Input your choice: " choice
            # case $choice in
            case $1 in
              "one")
            echo "Your choice is ONE"
            ;;
              "two")
            echo "Your choice is TWO"
            ;;
              "three")
            echo "Your choice is THREE"
            ;;
              *)
            echo "Usage {one|two|three}"
            ;;
            esac

             
            此時,您可以使用『 sh sh11.sh two 』的方式來下達指令,就可以收到相對應的響應了。 上面使用的是直接下達的方式,而如果使用 的是交互式時,那么將上面第 10, 11 行的 "#" 拿掉, 并將 12 行加上批注 (#),就可以讓使用者輸入參數啰~這樣是否很有趣啊?!



            --------------------------------------------------------------------------------
            利用 function 功能

            什么是『函數 (function)』功能啊?簡單的說,其實, 函數可以在 shell script 當中做出一個類似自訂執行指令的東西, 最大的功能是, 可以簡化我們很多的程序代碼~舉例來說,上面的 sh11.sh 當中,每個輸入結果 one, two, three 其實輸出的內容 都一樣啊~那么我就可以使用 function 來簡化了! function 的語法是這樣的:
            function fname() {
            程序段
            }

             
            那個 fname 就是我們的自訂的執行指令名稱~而程序段就是我們要他執行的內容了。 要注意的是,在 shell script 當中,  function 的設定一定要在程序的最前面, 這樣才能夠在執行時被找到可用的程序段喔!好~我們將 sh11.sh 改寫一下:
            [root@linux scripts]# vi sh11-2.sh
            #!/bin/bash
            # Program:
            #  Let user input one, two, three and show in screen.
            # History:
            2005/08/29 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            function printit(){
            echo -n "Your choice is "
            }

            echo "This program will print your selection !"
            case $1 in
              "one")
            printit; echo $1 | tr 'a-z' 'A-Z'
            ;;
              "two")
            printit; echo $1 | tr 'a-z' 'A-Z'
            ;;
              "three")
            printit; echo $1 | tr 'a-z' 'A-Z'
            ;;
              *)
            echo "Usage {one|two|three}"
            ;;
            esac

             
            以上面的例子來說,我做了一個函數名稱為 printif ,所以,當我在后續的程序段里面, 只要執行 printit 的話,就表示我的  shell script 要去執行『 function printit ....  里面的那幾個程序段落啰! 當然啰,上面這個例子舉得太簡單 了,所以您不會覺得 function 有什么好厲害的, 不過,如果某些程序代碼一再地在 script 當中重復時,這個 function 可就重 要的多啰~ 不但可以簡化程序代碼,而且可以做成類似『模塊』的玩意兒,真的很棒啦!

            另外, function 也是擁有內建變量的~他的內建變量與 shell script 很類似, 函數名稱代表示 $0 ,而后續接的變量 也是以 $1, $2... 來取代的~ 這里很容易搞錯喔~因為『 function fname() { 程序段 } 』內的 $0, $1...  等等與 shell script  $0 是不同的。以上面 sh11-2.sh 來說,假如我下達:『 sh sh11-2.sh one   表示在 shell script 內的 $1  "one" 這個字符串。但是在 printit() 內的 $1 則與這個 one 無關。 我們 將上面的例子再次的改寫一下,讓您更清楚!
            [root@linux scripts]# vi sh11-3.sh
            #!/bin/bash
            # Program:
            #  Let user input one, two, three and show in screen.
            # History:
            2005/08/29 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            function printit(){
            echo "Your choice is $1"
            }

            echo "This program will print your selection !"
            case $1 in
              "one")
            printit 1
            ;;
              "two")
            printit 2
            ;;
              "three")
            printit 3
            ;;
              *)
            echo "Usage {one|two|three}"
            ;;
            esac

             
            在上面的例子當中,如果您輸入『 sh sh11-3.sh one 』就會出現『 Your choice is 1 』的字樣~ 為什么是  1 呢?因為在程序段落當中,我們是寫了『 printit 1 』那個 1 就會成為 function 當中的 $1 喔~ 這樣是否理解呢?  function 本身其實比較困難一點,如果您還想要進行其它的撰寫的話。 不過,我們僅是想要更加了解 shell script 而已,所以,這 里看看即可~了解原理就好啰~ ^_^ 

            --------------------------------------------------------------------------------
            循環 (loop)

            除了 if...then...fi 這種條件判斷式之外,循環可能是程序當中最重要的一環了~ 循環可以不斷的執行某個程序段落,直到使用者設定的條件達成為止。 所以,重點是那個『條件的達成』是什么。底下我們就來談一談:


            --------------------------------------------------------------------------------
            while do done, until do done

            一般來說,循環最常見的就是底下這兩種狀態了:
            while [ condition ]
            do
            程序段落
            done

             
            這種方式中, while 是『當....時』,所以,這種方式說的是『當 condition 條件成立時,就進行循環,直到 condition 的條件不成立才停止』的意思。
            until [ condition ]
            do
            程序段落
            done

             
            這種方式恰恰與 while 相反,它說的是『當 condition 條件成立時,就終止循環, 否則就持續進行循環的程序段。』是否剛好相反 啊~我們以 while 來做個簡單的練習好了。 假設我要讓使用者輸入 yes 或者是 YES 才結束程序的執行,否則就一直進行告知使用者輸入字符 串。
            [root@linux scripts]# vi sh12.sh
            #!/bin/bash
            # Program:
            #  Use loop to try find your input.
            # History:
            2005/08/29 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            while [ "$yn" != "yes" ] && [ "$yn" != "YES" ]
            do
            read -p "Please input yes/YES to stop this program: " yn
            done

             
            上面這個例題的說明是『當 $yn 這個變量不是 "yes"  $yn 也不是 "YES" 時,才進行循環內的程序。』 而如果 $yn  "yes"  "YES" 時,就會離開循環啰~那如果使用 until 呢?呵呵有趣啰~ 他的條件會變成這樣:
            [root@linux scripts]# vi sh12-2.sh
            #!/bin/bash
            # Program:
            #  Use loop to try find your input.
            # History:
            2005/08/29 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            until [ "$yn" == "yes" ] || [ "$yn" == "YES" ]
            do
            read -p "Please input yes/YES to stop this program: " yn
            done

             
            仔細比對一下這兩個東西有啥不同喔! ^_^再來,如果我想要計算 1+2+3+....+100 這個數據呢? 利用循環啊~他是這樣的:
            [root@linux scripts]# vi sh13.sh
            #!/bin/bash
            # Program:
            #  Try to use loop to calculate the result "1+2+3...+100"
            # History:
            2005/08/29 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            s=0
            i=0
            while [ "$i" != "100" ]
            do
            i=$(($i+1))
            s=$(($s+$i))
            done
            echo "The result of '1+2+3+...+100' is ==> $s"

             
            嘿嘿!當您執行了『 sh sh13.sh 』之后,就可以得到 5050 這個數據才對啊!這樣瞭呼~ 那么讓您自行做一下,如果想要讓使用者 自行輸入一個數字,讓程序由 1+2+... 直到您輸入的數字為止, 該如何撰寫呢?應該很簡單吧?!答案可以參考一下習題練習里面的一題喔!



            --------------------------------------------------------------------------------
            for...do....done

            相對于 while, until 的循環方式是必須要『符合某個條件』的狀態, for 這種語法,則是『 已經知道要進行幾次循環』的狀態!他的語法是:
            for (( 
            初始值限制值執行步階 ))
            do
            程序段
            done

             
            這種語法適合于數值方式的運算當中,在 for 后面的括號內的三串內容意義為:
            初始值:某個變量在循環當中的起始值,直接以類似 i=1 設定好; 
            限制值:當變量的值在這個限制值的范圍內,就繼續進行循環。例如 i<=100 
            執行步階:每作一次循環時,變量的變化量。例如 i=i+1
            值得注意的是,在『執行步階』的設定上,如果每次增加 1 ,則可以使用類似『i++』的方式,亦即是 i 每次循環都會增加一的意思。好,我們以這種方式來進行 1 累加到 100 的循環吧!
            [root@linux scripts]# vi sh14.sh
            #!/bin/bash
            # Program:
            #  Try do calculate 1+2+....+100
            # History:
            2005/08/29 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            s=0
            for (( i=1; i<=100; i=i+1 ))
            do
            s=$(($s+$i))
            done
            echo "The result of '1+2+3+...+100' is ==> $s"

             
            一樣也是很簡單吧!利用這個 for 則可以直接限制循環要進行幾次呢!這么好用的東西難道只能在數值方面動作? 當然不是啦~我們還可以利用底下的方式來進行非數字方面的循環運作喔!
            for $var in con1 con2 con3 ...
            do
            程序段
            done

             
            以上面的例子來說,這個 $var 的變量內容在循環工作時:
            第一次循環時, $var 的內容為 con1  
            第二次循環時, $var 的內容為 con2  
            第三次循環時, $var 的內容為 con3  
            ....
            我們可以做個簡單的練習。假設我有三種動物,分別是 dog, cat, elephant 三種, 我想每一行都輸出這樣:『There are dogs...』之類的字樣,則可以:
            [root@linux scripts]# vi sh15.sh
            #!/bin/bash
            # Program:
            #  Using for .... loop to print 3 animal 
            # History:
            2005/08/29 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            for animal in dog cat elephant
            do
            echo "There are ""$animal""s.... "
            done

             
            很簡單是吧! ^_^。好了,那么如果我想要讓使用者輸入某個目錄, 然后我找出某目錄內的文件名的權限呢?又該如何是好?呵呵!可以這樣做啦~
            [root@linux scripts]# vi sh16.sh
            #!/bin/bash
            # Program:
            #  let user input a directory and find the whole file's permission.
            # History:
            2005/08/29 VBird First release
            PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
            export PATH

            # 1. 
            先看看這個目錄是否存在啊?
            read -p "Please input a directory: " dir
            if [ "$dir" == "" ] || [ ! -d "$dir" ]; then
            echo "The $dir is NOT exist in your system."
            exit 1
            fi

            # 2. 
            開始測試檔案啰~
            filelist=`ls $dir`
            for filename in $filelist
            do
            perm=""
            test -r "$dir/$filename" && perm="$perm readable"
            test -w "$dir/$filename" && perm="$perm writable"
            test -x "$dir/$filename" && perm="$perm executable"
            echo "The file $dir/$filename's permission is $perm "
            done

             
            呵呵!很有趣的例子吧~利用這種方式,您可以很輕易的來處理一些檔案的特性呢~ 我們循環就介紹到這里了~其它更多的應用,就得視您的需求來玩啰~。 

            --------------------------------------------------------------------------------
            shell script 
            的追蹤與 debug

            scripts 
            在執行之前,最怕的就是出現問題了!那么我們如何 debug 呢?有沒有辦法不需要透過直接執行該 scripts 就可以來判斷是否有問題呢!?呵呵! 當然是有的!我們就直接以 bash 的相關參數來進行判斷吧!
            [root@linux ~]# sh [-nvx] scripts.sh
            參數:
            -n  
            :不要執行 script,僅查詢語法的問題;
            -v  
            :再執行 sccript 前,先將 scripts 的內容輸出到屏幕上;
            -x  
            :將使用到的 script 內容顯示到屏幕上,這是很有用的參數!
            范例:

            范例一:測試 sh16.sh 有無語法的問題?
            [root@linux ~]# sh -n sh16.sh 
            若語法沒有問題,則不會顯示任何信息!

            范例二:將 sh15.sh 的執行過程全部列出來~
            [root@linux ~]# sh -x sh15.sh 
            + PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/home/vbird/bin
            + export PATH
            + for animal in dog cat elephant
            + echo 'There are dogs.... '
            There are dogs....
            + for animal in dog cat elephant
            + echo 'There are cats.... '
            There are cats....
            + for animal in dog cat elephant
            + echo 'There are elephants.... '
            There are elephants....
            使用 -x 真的是追蹤 script 的好方法,他可以將所有有執行的程序段在執行前列出來,
            如果是程序段落,則輸出時,最前面會加上 + 字號,表示他是程序代碼而已,
            實際的輸出則與 standard output 有關啊~如上所示。

             
            在上面的范例二當中,我們可以透過這個簡單的參數 -x 來達成 debug 的目的,這可是一個不可多得的參數, 通常如果您執行 script 卻發生問題時,利用這個 -x 參數,就可以知道問題是發生在哪一行上面了!

            熟悉 sh 的用法,將可以使您在管理 Linux 的過程中得心應手!至于在 Shell scripts 的學習方法上面,需要『多看、多模 仿、并加以修改成自己的樣式!』 是最快的學習手段了!網絡上有相當多的朋友在開發一些相當有用的 scripts ,若是您可以將對方的  scripts 拿來,并且改成適合自己主機的樣子!那么學習的效果會是最快的呢!

            另外,我們 Linux 系統本來就有很多的啟動 script ,如果您想要知道每個 script 所代表的功能是什么? 可以直接以  vi 進入該 script 去查閱一下,通常立刻就知道該 script 的目的了。 舉例來說,我們的 Linux 里頭有個文件名稱為:  /etc/init.d/portmap ,這個 script 是干嘛用的? 利用 vi 去查閱最前面的幾行字,他出現如下信息:
            # description: The portmapper manages RPC connections, which are used by \
            #              protocols such as NFS and NIS. The portmap server must be \
            #              running on machines which act as servers for protocols which \
            #              make use of the RPC mechanism.
            # processname: portmap

             
            簡單的說,他是被用在 NFS  NIS 上面的一個啟動 RPC  script  然后我們再利用 http: //www.google.com.tw 去搜尋一下 NFS, NIS  RPC  立刻就能夠知道這個 script 的功能啰~所以,下次您發 現不明的 script 時, 如果是系統提供的,那么利用這個檢查的方式,一定可以約略了解的啦! 加油的啰~ ^_^

            另外,本章所有的范例都可以在 http://linux.vbird.org/linux_basic/0340bashshell-scripts/scripts.tgz 里頭找到喔!加油~



            --------------------------------------------------------------------------------
            本章習題練習
            要看答案請將鼠標移動到『答:』底下的空白處,按下左鍵圈選空白處即可察看 ) 
            請建立一支 script ,當你執行該 script 的時候,該 script 可以顯示: 1. 你目前的身份 ( whoami ) 2. 你目前所在的目錄 ( pwd) 
            #!/bin/bash
            echo -e "Your name is ==> `whoami`"
            echo -e "The current directory is ==> `pwd`"

            請自行建立一支程序,該程序可以用來計算『您還有幾天可以過生日』啊?? 
            #!/bin/bash
            read -p "Pleas input your birthday (MMDD, ex> 0709): " bir
            now=`date +%m%d`
            if [ "$bir" == "$now" ]; then
            echo "Happy Birthday to you!!!"
            elif [ "$bir" -gt "$now" ]; then
            year=`date +%Y`
            total_d=$(($((`date --date="$year$bir" +%s`-`date +%s`))/60/60/24))
            echo "Your birthday will be $total_d later"
            else
            year=$((`date +%Y`+1))
            total_d=$(($((`date --date="$year$bir" +%s`-`date +%s`))/60/60/24))
            echo "Your birthday will be $total_d later"
            fi

            讓使用者輸入一個數字,程序可以由 1+2+3... 一直累加到使用者輸入的數字為止。 
            #!/bin/bash
            read -p "Please input an integer number: " number
            i=0
            s=0
            while [ "$i" != "$number" ]
            do
            i=$(($i+1))
            s=$(($s+$i))
            done
            echo "the result of '1+2+3+...$number' is ==> $s"

            撰寫一支程序,他的作用是: 1.) 先查看一下 /root/test/logical 這個名稱是否存在; 2.) 若不存在,則建立一個檔 案,使用 touch 來建立,建立完成后離開; 3.) 如果存在的話,判斷該名稱是否為檔案,若為檔案則將之刪除后建立一個檔案,檔名為  logical ,之后離開; 4.) 如果存在的話,而且該名稱為目錄,則移除此目錄! 
            #!/bin/bash
            if [ ! -e logical ]; then
            touch logical
            echo "Just make a file logical"
            exit 1
            elif [ -e logical ] && [ -f logical ]; then
            rm logical
            mkdir logical
            echo "remove file ==> logical"
            echo "and make directory logical"
            exit 1
            elif [ -e logical ] && [ -d logical ]; then
            rm -rf logical
            echo "remove directory ==> logical"
            exit 1
            else
            echo "Does here have anything?"
            fi

            我們知道 /etc/passwd 里面以 : 來分隔,第一欄為賬號名稱。請寫一只程序,可以將 /etc/passwd 的第一欄取出,而且每一欄都以一行字符串『The 1 account is "root" 』來顯示,那個 1 表示行數。 
            #!/bin/bash
            accounts=`cat /etc/passwd | cut -d':' -f1`
            for account in $accounts
            do
            declare -i i=$i+1
            echo "The $i account is \"$account\" "
            done

            posted on 2008-03-16 18:40 隨意門 閱讀(500) 評論(0)  編輯 收藏 引用

            久久福利青草精品资源站免费| 欧美亚洲另类久久综合| 久久精品国产清自在天天线| 99久久精品国产一区二区| 久久精品这里热有精品| 麻豆精品久久精品色综合| 国产精品一久久香蕉国产线看观看 | 久久久青草青青国产亚洲免观| 91精品国产综合久久婷婷| 久久人人爽人人爽人人片AV麻烦| 欧美久久综合九色综合| 婷婷久久综合| 人妻无码αv中文字幕久久琪琪布 人妻无码久久一区二区三区免费 人妻无码中文久久久久专区 | 日本精品久久久久影院日本| 亚洲第一永久AV网站久久精品男人的天堂AV| 国产成人99久久亚洲综合精品| 久久久无码精品亚洲日韩软件| 亚洲精品成人久久久| 亚洲精品白浆高清久久久久久| 久久精品国产精品亚洲| 国内精品久久久久久久97牛牛 | 色88久久久久高潮综合影院| 国内精品欧美久久精品| 久久99精品久久久久久久久久| 久久中文字幕精品| 久久精品国产欧美日韩| 91精品日韩人妻无码久久不卡| 亚洲va中文字幕无码久久 | 久久66热人妻偷产精品9| 亚洲国产成人久久综合一区77 | 一本一本久久a久久精品综合麻豆| 成人久久精品一区二区三区| 久久久婷婷五月亚洲97号色| 99精品国产免费久久久久久下载| 欧美激情精品久久久久久久| 国产精品久久久久一区二区三区 | 久久亚洲精品无码VA大香大香| 精品久久久久久无码中文野结衣| 久久r热这里有精品视频| 久久A级毛片免费观看| 欧美牲交A欧牲交aⅴ久久 |