linux-basic(13)学习shell script
生活随笔
收集整理的這篇文章主要介紹了
linux-basic(13)学习shell script
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
【13.1】什么是shell script?
1)shell script 是利用 shell 的功能所寫的一個『程序 (program)』,這個程序是使用純文字檔,將一些 shell 的語法與命令(含外部命令)寫在里面, 搭配正規表示法、管線命令與數據流重導向等功能,以達到我們所想要的處理目的。
【13.1.2】第一個 script 的編寫與執行
1)shell編寫規則:在 shell script 的撰寫中還需要用到底下的注意事項:
? ● 直接命令下達: shell.sh 文件必須要具備可讀與可運行 (rx) 的權限,然后:
? ? ? ○ 絕對路徑:使用 /home/dmtsai/shell.sh 來下達命令;
? ? ? ○ 相對路徑:假設工作目錄在 /home/dmtsai/ ,則使用 ./shell.sh 來運行
? ? ? ○ 變量『PATH』功能:將 shell.sh 放在 PATH 指定的目錄內,例如: ~/bin/
? ● 以 bash 程序來運行:透過『 bash shell.sh 』或『 sh shell.sh 』來運行
補充:那為何『 sh shell.sh 』也可以運行呢?這是因為 /bin/sh 其實就是 /bin/bash (連結檔),使用 sh shell.sh 亦即告訴系統,我想要直接以 bash 的功能來運行 shell.sh 這個文件內的相關命令的意思,所以此時你的 shell.sh 只要有 r 的權限即可被運行喔!
3)編寫第1個shell script
#!/bin/bash # Program: # This program shows "Hello World!" in your 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 (1)
【13.1.3】編寫shell script的良好習慣
1)建議你一定要養成良好的 script 撰寫習慣,在每個 script 的檔頭處記錄好:
? ● script 的功能;
? ● script 的版本資訊;
? ● script 的作者與聯絡方式;
? ● script 的版權宣告方式;
? ● script 的 History (歷史紀錄);
? ● script 內較特殊的命令,使用『絕對路徑』的方式來下達;
? ● script 運行時需要的環境變量預先聲明與設置。
【13.2】簡單的shell script練習
【13.2.1】簡單范例
1)交互式腳本:變量內容由用戶決定
請你以 read 命令的用途,撰寫一個 script ,他可以讓使用者輸入:1. first name 與 2. last name, 最后并且在螢幕上顯示:『Your full name is: 』的內容:
(2)
#!/bin/bash # Program: # User inputs his first name and last name. Program shows his full name. # History: # 2005/08/23 VBird First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATHread -p "Please input your first name: " firstname # 提示使用者輸入 read -p "Please input your last name: " lastname # 提示使用者輸入 echo -e "\nYour full name is: $firstname $lastname" # 結果由螢幕輸出
2)隨日期變化:利用日期進行文件的創建:
假設我想要創建三個空文件(透過touch) ,檔名最開頭由使用者輸入決定,假設使用者輸入 filename 好了,那今天的日期是 2009/02/14 , 我想要以前天、昨天、今天的日期來創建這些文件,亦即 filename_20090212, filename_20090213, filename_20090214 ,該如何是好?
[root@localhost scripts]# vim sh03.sh #!/bin/bash # Program: # Program creates three files, which named by user's input # and date command. # History: # 2018/05/01 tang rong 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 your filename: " 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"
(3)
(4)
3)數值運算:簡單的加減乘除
如果我們要使用者輸入兩個變量, 然后將兩個變量的內容相乘,最后輸出相乘的結果,那可以怎么做?
(5)
補充:鳥哥比較建議使用這樣的方式來進行運算:
var=$((運算內容))
不但容易記憶,而且也比較方便的多,因為兩個小括號內可以加上空白字節喔! 未來你可以使用這種方式來計算的呀!至於數值運算上的處理,則有:『 +, -, *, /, % 』等等。 那個 % 是取余數啦~舉例來說, 13 對 3 取余數,結果是 13=4*3+1,所以余數是 1 啊!就是:
(6)
【13.2.2】script的執行方式差別(source, sh script, ./script)
1)腳本的運行方式除了前面小節談到的方式之外,還可以利用 source 或小數點 (.) 來運行喔!那么這種運行方式有何不同呢?
方式1)利用直接執行的方式來執行script
當使用前一小節提到的直接命令下達 (不論是絕對路徑/相對路徑還是 $PATH 內),或者是利用 bash (或 sh) 來下達腳本時, 該 script 都會使用一個新的 bash 環境來運行腳本內的命令!也就是說,使用這種運行方式時, 其實 script 是在子程序的 bash 內運行的!
重點在于:『當子程序完成后,在子程序內的各項變量或動作將會結束而不會傳回到父程序中』!
【荔枝】我們舉剛剛提到過的 sh02.sh 這個腳本來說明好了,這個腳本可以讓使用者自行配置兩個變量,分別是 firstname 與 lastname,想一想,如果你直接運行該命令時,該命令幫你配置的 firstname 會不會生效?
(7)
1.2)利用source來執行腳本:在父進程中執行
(8)
1)判斷 /trong 這個目錄存在與否
(9)
2)那我知道 -e 是測試一個『東西』在不在, 如果還想要測試一下該檔名是啥玩意兒時,還有哪些標志可以來判斷的呢?呵呵!有底下這些東西喔!
(10)
(11)
3)OK!現在我們就利用 test 來幫我們寫幾個簡單的例子。首先,判斷一下,讓使用者輸入一個檔名,我們判斷:?
(13)
#!/bin/bash # Program: # User input a filename, program will check the flowing: # 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 "Please input a filename, I will check the filename's type and \ permission. \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 permissions are : $perm"
【13.3.2】利用判斷符號[]
1)除了我們很喜歡使用的 test 之外,其實,我們還可以利用判斷符號『 [ ] 』(就是中括號啦) 來進行數據的判斷呢! 舉例來說,如果我想要知道 $HOME 這個變量是否為空的,可以這樣做:
(14)
補充1:如果要在 bash 的語法當中使用中括號作為 shell 的判斷式時,必須要注意中括號的兩端需要有空白字節來分隔喔!
補充2)假設我空白鍵使用『□』符號來表示,那么,在這些地方你都需要有空白鍵:
(15)
所以說,你最好要注意:
? ● 在中括號 [] 內的每個組件都需要有空白鍵來分隔;
? ● 在中括號內的變量,最好都以雙引號括號起來;
? ● 在中括號內的常數,最好都以單或雙引號括號起來。
【荔枝】利用中括號[] 進行判斷,加引號的區別
(16)
【荔枝】那我們也使用中括號的判斷來做一個小案例好了,案例配置如下:
? 1. 當運行一個程序的時候,這個程序會讓使用者選擇 Y 或 N ,
? 2. 如果使用者輸入 Y 或 y 時,就顯示『 OK, continue 』
? 3. 如果使用者輸入 n 或 N 時,就顯示『 Oh, interrupt !』
? 4. 如果不是 Y/y/N/n 之內的其他字節,就顯示『 I don't know what your choice is 』
利用中括號[]、 && 與 || 來繼續吧!
(17)
【13.3.3】shell script的默認變量($0、 $1 ......)
1)如果你想要重新啟動系統登錄檔的功能,可以這樣做:
(18)
2)script 是怎么達成這個功能的呢?其實 script 針對參數已經有配置好一些變量名稱了!對應如下:
(19)
3)除了這些數字的變量之外, 我們還有一些較為特殊的變量可以在 script 內使用來調用這些參數喔!
? ● $# :代表后接的參數『個數』,以上表為例這里顯示為『 4 』;
? ● $@ :代表『 "$1" "$2" "$3" "$4" 』之意,每個變量是獨立的(用雙引號括起來);
? ● $* :代表『 "$1c$2c$3c$4" 』,其中 c 為分隔字節,默認為空白鍵, 所以本例中代表『 "$1 $2 $3 $4" 』之意。
【荔枝】假設我要運行一個可以攜帶參數的 script ,運行該腳本后螢幕會顯示如下的數據:
(20)
3)shift:造成參數變量號碼偏移
【荔枝】那個 shift 會移動變量,而且 shift 后面可以接數字,代表拿掉最前面的幾個參數的意思。
(21)
【13.4】條件判斷式
【13.4.1】利用 if...then
1)單層、簡單條件判斷式: 如果你只有一個判斷式要進行,那么我們可以簡單的這樣看:
(22)
1.1)如果我有多個條件要判別時,我還可以有多個中括號來隔開喔!而括號與括號之間,則以 && 或 || 來隔開,他們的意義是:
? ● && 代表 AND ;
? ● || 代表 or ;
1.2)所以,在使用中括號的判斷式中, && 及 || 就與命令下達的狀態不同了。舉例來說, sh06.sh 里面的判斷式可以這樣修改:
[ "$yn" == "Y" -o "$yn" == "y" ]
上式可替換為
[ "$yn" == "Y" ] || [ "$yn" == "y" ]
之所以這樣改,很多人是習慣問題!很多人則是喜歡一個中括號僅有一個判別式的原因。
【荔枝】將sh06.sh 修改為 if...then 的樣式看看:
(23)
2)多重、復雜條件判斷式
2.1)一個條件判斷
(24)
2.2)多個條件判斷
(25)
注意:你得要注意的是, elif 也是個判斷式,因此出現 elif 后面都要接 then 來處理!但是 else 已經是最后的沒有成立的結果了, 所以 else 后面并沒有 then 喔!好!我們來將 sh06-2.sh 改寫成這樣:
【荔枝】將 多個if 語句改為 elif 語句
(26)
3)一般來說,如果你不希望使用者由鍵盤輸入額外的數據時, 可以使用上一節提到的參數功能 ($1)!讓使用者在下達命令時就將參數帶進去! 現在我們想讓使用者輸入『 hello 』這個關鍵字時,利用參數的方法可以這樣依序設計:
? 1. 判斷 $1 是否為 hello,如果是的話,就顯示 "Hello, how are you ?";
? 2. 如果沒有加任何參數,就提示使用者必須要使用的參數下達法;
? 3. 而如果加入的參數不是 hello ,就提醒使用者僅能使用 hello 為參數。
整個程序的撰寫可以是這樣的:
(27)
【荔枝】 netstat命令:查詢到目前主機打開的網絡服務端口
荔枝1)我可以利用『 netstat -tuln 』來取得目前主機有啟動的服務:
(28)
補充:上面的重點是『Local Address (本地主機的IP與端口對應)』那個欄位,他代表的是本機所啟動的網絡服務! IP的部分說明的是該服務位於那個介面上,若為 127.0.0.1 則是僅針對本機開放,若是 0.0.0.0 或 ::: 則代表對整個 Internet 開放。 每個端口 (port) 都有其特定的網絡服務,幾個常見的 port 與相關網絡服務的關系是:
? ● 80: WWW
? ● 22: ssh
? ● 21: ftp
? ● 25: mail
? ● 111: RPC(遠程程序呼叫)
? ● 631: CUPS(列印服務功能)
荔枝2)假設我的主機有興趣要偵測的是比較常見的 port 21, 22, 25及 80 時,那我如何透過 netstat 去偵測我的主機是否有開啟這四個主要的網絡服務端口呢?由於每個服務的關鍵字都是接在冒號『 : 』后面, 所以可以藉由擷取類似『 :80 』來偵測的!那我就可以簡單的這樣去寫這個程序喔:
(29)
【荔枝】寫個腳本程序來跑,讓使用者輸入他的退伍日期,讓你去幫他計算還有幾天才退伍?
由於日期是要用相減的方式來處置,所以我們可以透過使用 date 顯示日期與時間,將他轉為由 1970-01-01 累積而來的秒數, 透過秒數相減來取得剩余的秒數后,再換算為日數即可。整個腳本的制作流程有點像這樣:
? 1. 先讓使用者輸入他們的退伍日期;
? 2. 再由現在日期比對退伍日期;
? 3. 由兩個日期的比較來顯示『還需要幾天』才能夠退伍的字樣。
似乎挺難的樣子?其實也不會啦,利用『 date --date="YYYYMMDD" +%s 』轉成秒數后,接下來的動作就容易的多了!
(30)
#!/bin/bash # Program: # You input your demobilization date, I calculate how many days # before you demobilize. # 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 before your demobilization date..." read -p "Please input your demobilization date (YYYYMMDD ex>20090401): " date2# 2. 測試一下,這個輸入的內容是否正確?利用正規表示法羅~ date_d=$(echo $date2 |grep '[0-9]\{8\}') # 看看是否有八個數字 if [ "$date_d" == "" ]; thenecho "You input the wrong date format...."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" elsedeclare -i date_h=$(($(($date_total_s-$date_d*60*60*24))/60/60))echo "You will demobilize after $date_d days and $date_h hours." fi
(31)
【13.4.2】利用 case...esac 判斷
(32)
【荔枝】把 sh09.sh 修改一下,如下:
(33)
#!/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 PATHcase $1 in"hello")echo "Hello, how are you ?";;"")echo "You MUST input parameters, ex> {$0 someword}";;*) # 其實就相當於萬用字節,0~無窮多個任意字節之意!echo "Usage $0 {hello}";; esac
(34)
【補充】一般來說,使用『 case $變量 in 』這個語法中,當中的那個『 $變量 』大致有兩種取得的方式:
? ● 直接下達式:例如上面提到的,利用『 script.sh variable 』 的方式來直接給予 $1 這個變量的內容,這也是在 /etc/init.d 目錄下大多數程序的設計方式。
? ● 互動式:透過 read 這個命令來讓使用者輸入變量的內容。
【荔枝】讓使用者能夠輸入 one, two, three , 并且將使用者的變量顯示到屏幕上,如果不是 one, two, three 時,就告知使用者僅有這三種選擇。(通過直接執行式來傳入參數,即利用 script.sh variable 的方式來直接給予 $1 這個變量的內容)
(35)?
#!/bin/bash # Program: # This script only accepts the flowing parameter: one, two or three. # History: # 2005/08/29 VBird First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATHecho "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 $0 {one|two|three}";; esac 【繼續荔枝】讓使用者能夠輸入 one, two, three , 并且將使用者的變量顯示到屏幕上,如果不是 one, two, three 時,就告知使用者僅有這三種選擇。(通過read命令讀入用戶輸入的變量內容)
(36)
【13.4.3】利用function功能
1)function的語法如下:
function fname() {
程序段
}
那個 fname 就是我們的自訂的運行命令名稱~而程序段就是我們要他運行的內容了。 要注意的是,因為 shell script 的運行方式是由上而下,由左而右, 因此在 shell script 當中的 function 的配置一定要在程序的最前面, 這樣才能夠在運行時被找到可用的程序段喔!
【荔枝】定義一個名為 printit的函數, 如下:
(37)
#!/bin/bash # Program: # Use function to repeat information. # History: # 2005/08/29 VBird First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATHfunction printit(){echo -n "Your choice is " # 加上 -n 可以不斷行繼續在同一行顯示 }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 $0 {one|two|three}";; esac2)另外, function 也是擁有內建變量的~他的內建變量與 shell script 很類似, 函數名稱代表示 $0 ,而后續接的變量也是以 $1, $2... 來取代的~ 這里很容易搞錯喔~因為『 function fname() { 程序段 } 』內的 $0, $1... 等等與 shell script 的 $0 是不同的。以上面 sh12-2.sh 來說,假如我下達:『 sh sh12-2.sh one 』 這表示在 shell script 內的 $1 為 "one" 這個字串。但是在 printit() 內的 $1 則與這個 one 無關。?
【荔枝】將上面的例子再次改寫一下,如下:
(38)
[root@localhost scripts]# vim sh12-4.sh#!/bin/bash # Program: # Use function to repeat information. # History: # 2005/08/29 VBird First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATHfunction printit(){echo "Your choice is $1" # 這個 $1 必須要參考底下命令的下達 }echo "This program will print your selection !" case $1 in"one")printit 1 # 請注意, printit 命令后面還有接參數!;;"two")printit 2;;"three")printit 3;;*)echo "Usage $0 {one|two|three}";; esac 【13.5】循環
【13.5.1】while do done, until do done (不定循環)
1)循環方式
方式1) while do done 循環:while 的中文是當....時,所以,這種方式說的是『當 condition 條件成立時,就進行循環,直到 condition 的條件不成立才停止』的意思。
(39)
方式2)until do done 循環(不定循環):它說的是當 condition 條件成立時,就終止循環, 否則就持續進行循環的程序段。
(40)
【荔枝】while循環:假設我要讓使用者輸入 yes 或者是 YES 才結束程序的運行,否則就一直進行告知使用者輸入字串。
(41)
(42)
【荔枝】想要計算 1+2+3+....+100 這個數據呢? 利用循環啊。
(43)
【13.5.2】for...do...done(固定循環)
1)相對于 while, until 的循環方式是必須要『符合某個條件』的狀態, for 這種語法,則是已經知道要進行幾次循環的狀態!他的語法是:
(44)
2)讓我們想像另外一種狀況,由於系統上面的各種帳號都是寫在 /etc/passwd 內的第一個欄位,你能不能透過管線命令的 cut 捉出單純的帳號名稱后,以 id 及 finger 分別檢查使用者的識別碼與特殊參數呢?
(45)
【補充】
補充1)id命令: id 命令可以顯示真實有效的用戶 ID(UID) 和組 ID(GID)。UID 是對一個用戶的單一身份標識。組 ID(GID)則對應多個UID。
補充2)finger命令:finger命令用于查找并顯示用戶信息。包括本地與遠端主機的用戶皆可,帳號名稱沒有大小寫的差別。單獨執行finger指令,它會顯示本地主機現在所有的用戶的登陸信息,包括帳號名稱,真實姓名,登入終端機,閑置時間,登入時間以及地址和電話。
(46)
【荔枝】利用 ping 這個可以判斷網絡狀態的命令, 來進行網絡狀態的實際偵測時,我想要偵測的網域是本機所在的 192.168.1.1~192.168.1.100,由於有 100 臺主機, 總不會要我在 for 后面輸入 1 到 100 吧?此時你可以這樣做喔!(但本機實驗只取10臺機器!!)
(47)
#!/bin/bash # Program # Use ping command to check the network's PC state. # History # 2009/02/18 VBird first release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH network="192.168.1" # 先定義一個網域的前面部分! for sitenu in $(seq 1 10) # seq 為 sequence(連續) 的縮寫之意 do# 底下的程序在取得 ping 的回傳值是正確的還是失敗的!ping -c 1 -w 1 ${network}.${sitenu} &> /dev/null && result=0 || result=1# 開始顯示結果是正確的啟動 (UP) 還是錯誤的沒有連通 (DOWN)if [ "$result" == 0 ]; thenecho "Server ${network}.${sitenu} is UP."elseecho "Server ${network}.${sitenu} is DOWN."fi done 【荔枝】編寫判別式加上循環的功能: 我想要讓使用者輸入某個目錄文件名, 然后找出某目錄內的文件名權限,該如何是好?
(48)
(49)
【13.5.3】for...do...done 的數值處理
1)for 循環還有另外一種寫法!語法如下:
(50)
2)這種語法適合於數值方式的運算當中,在 for 后面的括號內的三串內容意義為:
? ● 初始值:某個變量在回圈當中的起始值,直接以類似 i=1 配置好;
? ● 限制值:當變量的值在這個限制值的范圍內,就繼續進行回圈。例如 i<=100;
? ● 運行步階:每作一次回圈時,變量的變化量。例如 i=i+1。?
【荔枝】執行從1的累加,上限是輸入的數字,如下:
(51)
【13.6】shell script的追蹤與調試
1)scripts 在運行之前,最怕的就是出現語法錯誤的問題了!那么我們如何 debug 呢? 有沒有辦法不需要透過直接運行該 scripts 就可以來判斷是否有問題呢?呵呵!當然是有的!我們就直接以 bash 的相關參數來進行判斷吧!
(52)
【荔枝】
(53)
(54)
1)shell script 是利用 shell 的功能所寫的一個『程序 (program)』,這個程序是使用純文字檔,將一些 shell 的語法與命令(含外部命令)寫在里面, 搭配正規表示法、管線命令與數據流重導向等功能,以達到我們所想要的處理目的。
- 1.1)簡單的說, shell script 就像是早期 DOS 年代的批量檔 (.bat) ,最簡單的功能就是將許多命令匯整寫在一起, 讓使用者很輕易的就能夠 one touch 的方法去處理復雜的動作 (運行一個文件 "shell script" ,就能夠一次運行多個命令)。 而且 shell script 更提供陣列、回圈、條件與邏輯判斷等重要功能,讓使用者也可以直接以 shell 來撰寫程序,而不必使用類似 C 程序語言等傳統程序撰寫的語法呢!?
- 1.2)shell script 可以簡單的被看成是批量檔, 也可以被說成是一個程序語言,且這個程序語言由於都是利用 shell 與相關工具命令, 所以不需要編譯即可運行,且擁有不錯的除錯 (debug) 工具,所以,他可以幫助系統管理員快速的管理好主機。
【13.1.2】第一個 script 的編寫與執行
1)shell編寫規則:在 shell script 的撰寫中還需要用到底下的注意事項:
- ? 1. 命令的運行是從上而下、從左而右的分析與運行;
- ? 2. 命令的下達就如同第五章內提到的: 命令、選項與參數間的多個空白都會被忽略掉;
- ? 3. 空白行也將被忽略掉,并且 [tab] 按鍵所推開的空白同樣視為空白鍵;
- ? 4. 如果讀取到一個 Enter 符號 (CR) ,就嘗試開始運行該行 (或該串) 命令;
- ? 5. 至於如果一行的內容太多,則可以使用『 \[Enter] 』來延伸至下一行;
- ? 6. 『 # 』可做為注解!任何加在 # 后面的數據將全部被視為注解文字而被忽略!
? ● 直接命令下達: shell.sh 文件必須要具備可讀與可運行 (rx) 的權限,然后:
? ? ? ○ 絕對路徑:使用 /home/dmtsai/shell.sh 來下達命令;
? ? ? ○ 相對路徑:假設工作目錄在 /home/dmtsai/ ,則使用 ./shell.sh 來運行
? ? ? ○ 變量『PATH』功能:將 shell.sh 放在 PATH 指定的目錄內,例如: ~/bin/
? ● 以 bash 程序來運行:透過『 bash shell.sh 』或『 sh shell.sh 』來運行
補充:那為何『 sh shell.sh 』也可以運行呢?這是因為 /bin/sh 其實就是 /bin/bash (連結檔),使用 sh shell.sh 亦即告訴系統,我想要直接以 bash 的功能來運行 shell.sh 這個文件內的相關命令的意思,所以此時你的 shell.sh 只要有 r 的權限即可被運行喔!
3)編寫第1個shell script
#!/bin/bash # Program: # This program shows "Hello World!" in your 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 (1)
【13.1.3】編寫shell script的良好習慣
1)建議你一定要養成良好的 script 撰寫習慣,在每個 script 的檔頭處記錄好:
? ● script 的功能;
? ● script 的版本資訊;
? ● script 的作者與聯絡方式;
? ● script 的版權宣告方式;
? ● script 的 History (歷史紀錄);
? ● script 內較特殊的命令,使用『絕對路徑』的方式來下達;
? ● script 運行時需要的環境變量預先聲明與設置。
【13.2】簡單的shell script練習
【13.2.1】簡單范例
1)交互式腳本:變量內容由用戶決定
請你以 read 命令的用途,撰寫一個 script ,他可以讓使用者輸入:1. first name 與 2. last name, 最后并且在螢幕上顯示:『Your full name is: 』的內容:
(2)
#!/bin/bash # Program: # User inputs his first name and last name. Program shows his full name. # History: # 2005/08/23 VBird First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATHread -p "Please input your first name: " firstname # 提示使用者輸入 read -p "Please input your last name: " lastname # 提示使用者輸入 echo -e "\nYour full name is: $firstname $lastname" # 結果由螢幕輸出
2)隨日期變化:利用日期進行文件的創建:
假設我想要創建三個空文件(透過touch) ,檔名最開頭由使用者輸入決定,假設使用者輸入 filename 好了,那今天的日期是 2009/02/14 , 我想要以前天、昨天、今天的日期來創建這些文件,亦即 filename_20090212, filename_20090213, filename_20090214 ,該如何是好?
[root@localhost scripts]# vim sh03.sh #!/bin/bash # Program: # Program creates three files, which named by user's input # and date command. # History: # 2018/05/01 tang rong 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 your filename: " 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"
(3)
(4)
3)數值運算:簡單的加減乘除
如果我們要使用者輸入兩個變量, 然后將兩個變量的內容相乘,最后輸出相乘的結果,那可以怎么做?
(5)
補充:鳥哥比較建議使用這樣的方式來進行運算:
var=$((運算內容))
不但容易記憶,而且也比較方便的多,因為兩個小括號內可以加上空白字節喔! 未來你可以使用這種方式來計算的呀!至於數值運算上的處理,則有:『 +, -, *, /, % 』等等。 那個 % 是取余數啦~舉例來說, 13 對 3 取余數,結果是 13=4*3+1,所以余數是 1 啊!就是:
(6)
【13.2.2】script的執行方式差別(source, sh script, ./script)
1)腳本的運行方式除了前面小節談到的方式之外,還可以利用 source 或小數點 (.) 來運行喔!那么這種運行方式有何不同呢?
方式1)利用直接執行的方式來執行script
當使用前一小節提到的直接命令下達 (不論是絕對路徑/相對路徑還是 $PATH 內),或者是利用 bash (或 sh) 來下達腳本時, 該 script 都會使用一個新的 bash 環境來運行腳本內的命令!也就是說,使用這種運行方式時, 其實 script 是在子程序的 bash 內運行的!
重點在于:『當子程序完成后,在子程序內的各項變量或動作將會結束而不會傳回到父程序中』!
【荔枝】我們舉剛剛提到過的 sh02.sh 這個腳本來說明好了,這個腳本可以讓使用者自行配置兩個變量,分別是 firstname 與 lastname,想一想,如果你直接運行該命令時,該命令幫你配置的 firstname 會不會生效?
(7)
1.2)利用source來執行腳本:在父進程中執行
(8)
【13.3】善用判斷式
【13.3.1】利用test命令的測試功能1)判斷 /trong 這個目錄存在與否
(9)
2)那我知道 -e 是測試一個『東西』在不在, 如果還想要測試一下該檔名是啥玩意兒時,還有哪些標志可以來判斷的呢?呵呵!有底下這些東西喔!
(10)
(11)
3)OK!現在我們就利用 test 來幫我們寫幾個簡單的例子。首先,判斷一下,讓使用者輸入一個檔名,我們判斷:?
- 判斷1)這個文件是否存在,若不存在則給予一個『Filename does not exist』的信息,并中斷程序;
- 判斷2)若這個文件存在,則判斷他是個文件或目錄,結果輸出『Filename is regular file』或 『Filename is directory』;
- 判斷3)判斷一下,運行者的身份對這個文件或目錄所擁有的權限,并輸出權限數據!
(13)
#!/bin/bash # Program: # User input a filename, program will check the flowing: # 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 "Please input a filename, I will check the filename's type and \ permission. \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 permissions are : $perm"
【13.3.2】利用判斷符號[]
1)除了我們很喜歡使用的 test 之外,其實,我們還可以利用判斷符號『 [ ] 』(就是中括號啦) 來進行數據的判斷呢! 舉例來說,如果我想要知道 $HOME 這個變量是否為空的,可以這樣做:
(14)
補充1:如果要在 bash 的語法當中使用中括號作為 shell 的判斷式時,必須要注意中括號的兩端需要有空白字節來分隔喔!
補充2)假設我空白鍵使用『□』符號來表示,那么,在這些地方你都需要有空白鍵:
(15)
所以說,你最好要注意:
? ● 在中括號 [] 內的每個組件都需要有空白鍵來分隔;
? ● 在中括號內的變量,最好都以雙引號括號起來;
? ● 在中括號內的常數,最好都以單或雙引號括號起來。
【荔枝】利用中括號[] 進行判斷,加引號的區別
(16)
【荔枝】那我們也使用中括號的判斷來做一個小案例好了,案例配置如下:
? 1. 當運行一個程序的時候,這個程序會讓使用者選擇 Y 或 N ,
? 2. 如果使用者輸入 Y 或 y 時,就顯示『 OK, continue 』
? 3. 如果使用者輸入 n 或 N 時,就顯示『 Oh, interrupt !』
? 4. 如果不是 Y/y/N/n 之內的其他字節,就顯示『 I don't know what your choice is 』
利用中括號[]、 && 與 || 來繼續吧!
(17)
【13.3.3】shell script的默認變量($0、 $1 ......)
1)如果你想要重新啟動系統登錄檔的功能,可以這樣做:
(18)
2)script 是怎么達成這個功能的呢?其實 script 針對參數已經有配置好一些變量名稱了!對應如下:
(19)
3)除了這些數字的變量之外, 我們還有一些較為特殊的變量可以在 script 內使用來調用這些參數喔!
? ● $# :代表后接的參數『個數』,以上表為例這里顯示為『 4 』;
? ● $@ :代表『 "$1" "$2" "$3" "$4" 』之意,每個變量是獨立的(用雙引號括起來);
? ● $* :代表『 "$1c$2c$3c$4" 』,其中 c 為分隔字節,默認為空白鍵, 所以本例中代表『 "$1 $2 $3 $4" 』之意。
【荔枝】假設我要運行一個可以攜帶參數的 script ,運行該腳本后螢幕會顯示如下的數據:
- ? ● 程序的檔名為何?
- ? ● 共有幾個參數?
- ? ● 若參數的個數小於 2 則告知使用者參數數量太少
- ? ● 全部的參數內容為何?
- ? ● 第一個參數為何?
- ? ● 第二個參數為何。
(20)
3)shift:造成參數變量號碼偏移
【荔枝】那個 shift 會移動變量,而且 shift 后面可以接數字,代表拿掉最前面的幾個參數的意思。
(21)
【13.4】條件判斷式
【13.4.1】利用 if...then
1)單層、簡單條件判斷式: 如果你只有一個判斷式要進行,那么我們可以簡單的這樣看:
(22)
1.1)如果我有多個條件要判別時,我還可以有多個中括號來隔開喔!而括號與括號之間,則以 && 或 || 來隔開,他們的意義是:
? ● && 代表 AND ;
? ● || 代表 or ;
1.2)所以,在使用中括號的判斷式中, && 及 || 就與命令下達的狀態不同了。舉例來說, sh06.sh 里面的判斷式可以這樣修改:
[ "$yn" == "Y" -o "$yn" == "y" ]
上式可替換為
[ "$yn" == "Y" ] || [ "$yn" == "y" ]
之所以這樣改,很多人是習慣問題!很多人則是喜歡一個中括號僅有一個判別式的原因。
【荔枝】將sh06.sh 修改為 if...then 的樣式看看:
(23)
2)多重、復雜條件判斷式
2.1)一個條件判斷
(24)
2.2)多個條件判斷
(25)
注意:你得要注意的是, elif 也是個判斷式,因此出現 elif 后面都要接 then 來處理!但是 else 已經是最后的沒有成立的結果了, 所以 else 后面并沒有 then 喔!好!我們來將 sh06-2.sh 改寫成這樣:
【荔枝】將 多個if 語句改為 elif 語句
(26)
3)一般來說,如果你不希望使用者由鍵盤輸入額外的數據時, 可以使用上一節提到的參數功能 ($1)!讓使用者在下達命令時就將參數帶進去! 現在我們想讓使用者輸入『 hello 』這個關鍵字時,利用參數的方法可以這樣依序設計:
? 1. 判斷 $1 是否為 hello,如果是的話,就顯示 "Hello, how are you ?";
? 2. 如果沒有加任何參數,就提示使用者必須要使用的參數下達法;
? 3. 而如果加入的參數不是 hello ,就提醒使用者僅能使用 hello 為參數。
整個程序的撰寫可以是這樣的:
(27)
【荔枝】 netstat命令:查詢到目前主機打開的網絡服務端口
荔枝1)我可以利用『 netstat -tuln 』來取得目前主機有啟動的服務:
(28)
補充:上面的重點是『Local Address (本地主機的IP與端口對應)』那個欄位,他代表的是本機所啟動的網絡服務! IP的部分說明的是該服務位於那個介面上,若為 127.0.0.1 則是僅針對本機開放,若是 0.0.0.0 或 ::: 則代表對整個 Internet 開放。 每個端口 (port) 都有其特定的網絡服務,幾個常見的 port 與相關網絡服務的關系是:
? ● 80: WWW
? ● 22: ssh
? ● 21: ftp
? ● 25: mail
? ● 111: RPC(遠程程序呼叫)
? ● 631: CUPS(列印服務功能)
荔枝2)假設我的主機有興趣要偵測的是比較常見的 port 21, 22, 25及 80 時,那我如何透過 netstat 去偵測我的主機是否有開啟這四個主要的網絡服務端口呢?由於每個服務的關鍵字都是接在冒號『 : 』后面, 所以可以藉由擷取類似『 :80 』來偵測的!那我就可以簡單的這樣去寫這個程序喔:
(29)
【荔枝】寫個腳本程序來跑,讓使用者輸入他的退伍日期,讓你去幫他計算還有幾天才退伍?
由於日期是要用相減的方式來處置,所以我們可以透過使用 date 顯示日期與時間,將他轉為由 1970-01-01 累積而來的秒數, 透過秒數相減來取得剩余的秒數后,再換算為日數即可。整個腳本的制作流程有點像這樣:
? 1. 先讓使用者輸入他們的退伍日期;
? 2. 再由現在日期比對退伍日期;
? 3. 由兩個日期的比較來顯示『還需要幾天』才能夠退伍的字樣。
似乎挺難的樣子?其實也不會啦,利用『 date --date="YYYYMMDD" +%s 』轉成秒數后,接下來的動作就容易的多了!
(30)
#!/bin/bash # Program: # You input your demobilization date, I calculate how many days # before you demobilize. # 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 before your demobilization date..." read -p "Please input your demobilization date (YYYYMMDD ex>20090401): " date2# 2. 測試一下,這個輸入的內容是否正確?利用正規表示法羅~ date_d=$(echo $date2 |grep '[0-9]\{8\}') # 看看是否有八個數字 if [ "$date_d" == "" ]; thenecho "You input the wrong date format...."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" elsedeclare -i date_h=$(($(($date_total_s-$date_d*60*60*24))/60/60))echo "You will demobilize after $date_d days and $date_h hours." fi
(31)
【13.4.2】利用 case...esac 判斷
(32)
【荔枝】把 sh09.sh 修改一下,如下:
(33)
#!/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 PATHcase $1 in"hello")echo "Hello, how are you ?";;"")echo "You MUST input parameters, ex> {$0 someword}";;*) # 其實就相當於萬用字節,0~無窮多個任意字節之意!echo "Usage $0 {hello}";; esac
(34)
【補充】一般來說,使用『 case $變量 in 』這個語法中,當中的那個『 $變量 』大致有兩種取得的方式:
? ● 直接下達式:例如上面提到的,利用『 script.sh variable 』 的方式來直接給予 $1 這個變量的內容,這也是在 /etc/init.d 目錄下大多數程序的設計方式。
? ● 互動式:透過 read 這個命令來讓使用者輸入變量的內容。
【荔枝】讓使用者能夠輸入 one, two, three , 并且將使用者的變量顯示到屏幕上,如果不是 one, two, three 時,就告知使用者僅有這三種選擇。(通過直接執行式來傳入參數,即利用 script.sh variable 的方式來直接給予 $1 這個變量的內容)
(35)?
#!/bin/bash # Program: # This script only accepts the flowing parameter: one, two or three. # History: # 2005/08/29 VBird First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATHecho "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 $0 {one|two|three}";; esac 【繼續荔枝】讓使用者能夠輸入 one, two, three , 并且將使用者的變量顯示到屏幕上,如果不是 one, two, three 時,就告知使用者僅有這三種選擇。(通過read命令讀入用戶輸入的變量內容)
(36)
【13.4.3】利用function功能
1)function的語法如下:
function fname() {
程序段
}
那個 fname 就是我們的自訂的運行命令名稱~而程序段就是我們要他運行的內容了。 要注意的是,因為 shell script 的運行方式是由上而下,由左而右, 因此在 shell script 當中的 function 的配置一定要在程序的最前面, 這樣才能夠在運行時被找到可用的程序段喔!
【荔枝】定義一個名為 printit的函數, 如下:
(37)
#!/bin/bash # Program: # Use function to repeat information. # History: # 2005/08/29 VBird First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATHfunction printit(){echo -n "Your choice is " # 加上 -n 可以不斷行繼續在同一行顯示 }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 $0 {one|two|three}";; esac2)另外, function 也是擁有內建變量的~他的內建變量與 shell script 很類似, 函數名稱代表示 $0 ,而后續接的變量也是以 $1, $2... 來取代的~ 這里很容易搞錯喔~因為『 function fname() { 程序段 } 』內的 $0, $1... 等等與 shell script 的 $0 是不同的。以上面 sh12-2.sh 來說,假如我下達:『 sh sh12-2.sh one 』 這表示在 shell script 內的 $1 為 "one" 這個字串。但是在 printit() 內的 $1 則與這個 one 無關。?
【荔枝】將上面的例子再次改寫一下,如下:
(38)
[root@localhost scripts]# vim sh12-4.sh#!/bin/bash # Program: # Use function to repeat information. # History: # 2005/08/29 VBird First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATHfunction printit(){echo "Your choice is $1" # 這個 $1 必須要參考底下命令的下達 }echo "This program will print your selection !" case $1 in"one")printit 1 # 請注意, printit 命令后面還有接參數!;;"two")printit 2;;"three")printit 3;;*)echo "Usage $0 {one|two|three}";; esac 【13.5】循環
【13.5.1】while do done, until do done (不定循環)
1)循環方式
方式1) while do done 循環:while 的中文是當....時,所以,這種方式說的是『當 condition 條件成立時,就進行循環,直到 condition 的條件不成立才停止』的意思。
(39)
方式2)until do done 循環(不定循環):它說的是當 condition 條件成立時,就終止循環, 否則就持續進行循環的程序段。
(40)
【荔枝】while循環:假設我要讓使用者輸入 yes 或者是 YES 才結束程序的運行,否則就一直進行告知使用者輸入字串。
(41)
(42)
【荔枝】想要計算 1+2+3+....+100 這個數據呢? 利用循環啊。
(43)
【13.5.2】for...do...done(固定循環)
1)相對于 while, until 的循環方式是必須要『符合某個條件』的狀態, for 這種語法,則是已經知道要進行幾次循環的狀態!他的語法是:
(44)
2)讓我們想像另外一種狀況,由於系統上面的各種帳號都是寫在 /etc/passwd 內的第一個欄位,你能不能透過管線命令的 cut 捉出單純的帳號名稱后,以 id 及 finger 分別檢查使用者的識別碼與特殊參數呢?
(45)
【補充】
補充1)id命令: id 命令可以顯示真實有效的用戶 ID(UID) 和組 ID(GID)。UID 是對一個用戶的單一身份標識。組 ID(GID)則對應多個UID。
補充2)finger命令:finger命令用于查找并顯示用戶信息。包括本地與遠端主機的用戶皆可,帳號名稱沒有大小寫的差別。單獨執行finger指令,它會顯示本地主機現在所有的用戶的登陸信息,包括帳號名稱,真實姓名,登入終端機,閑置時間,登入時間以及地址和電話。
(46)
【荔枝】利用 ping 這個可以判斷網絡狀態的命令, 來進行網絡狀態的實際偵測時,我想要偵測的網域是本機所在的 192.168.1.1~192.168.1.100,由於有 100 臺主機, 總不會要我在 for 后面輸入 1 到 100 吧?此時你可以這樣做喔!(但本機實驗只取10臺機器!!)
(47)
#!/bin/bash # Program # Use ping command to check the network's PC state. # History # 2009/02/18 VBird first release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH network="192.168.1" # 先定義一個網域的前面部分! for sitenu in $(seq 1 10) # seq 為 sequence(連續) 的縮寫之意 do# 底下的程序在取得 ping 的回傳值是正確的還是失敗的!ping -c 1 -w 1 ${network}.${sitenu} &> /dev/null && result=0 || result=1# 開始顯示結果是正確的啟動 (UP) 還是錯誤的沒有連通 (DOWN)if [ "$result" == 0 ]; thenecho "Server ${network}.${sitenu} is UP."elseecho "Server ${network}.${sitenu} is DOWN."fi done 【荔枝】編寫判別式加上循環的功能: 我想要讓使用者輸入某個目錄文件名, 然后找出某目錄內的文件名權限,該如何是好?
(48)
(49)
【13.5.3】for...do...done 的數值處理
1)for 循環還有另外一種寫法!語法如下:
(50)
2)這種語法適合於數值方式的運算當中,在 for 后面的括號內的三串內容意義為:
? ● 初始值:某個變量在回圈當中的起始值,直接以類似 i=1 配置好;
? ● 限制值:當變量的值在這個限制值的范圍內,就繼續進行回圈。例如 i<=100;
? ● 運行步階:每作一次回圈時,變量的變化量。例如 i=i+1。?
【荔枝】執行從1的累加,上限是輸入的數字,如下:
(51)
【13.6】shell script的追蹤與調試
1)scripts 在運行之前,最怕的就是出現語法錯誤的問題了!那么我們如何 debug 呢? 有沒有辦法不需要透過直接運行該 scripts 就可以來判斷是否有問題呢?呵呵!當然是有的!我們就直接以 bash 的相關參數來進行判斷吧!
(52)
【荔枝】
(53)
(54)
- 補充1) 在輸出的信息中,在加號后面的數據其實都是命令串,由於 sh -x 的方式來將命令運行過程也顯示出來, 如此使用者可以判斷程序碼運行到哪一段時會出現相關的資訊!這個功能非常的棒!
- 補充2)Linux 系統本來就有很多的服務啟動腳本,如果你想要知道每個 script 所代表的功能是什么? 可以直接以 vim 進入該 script 去查閱一下,通常立刻就知道該 script 的目的了。 舉例來說,我們之前一直提到的 /etc/init.d/syslog ,這個 script 是干嘛用的? 利用 vi 去查閱最前面的幾行字,就知道這個 shell 腳本是干什么的了。
- ? shell script 是利用 shell 的功能所寫的一個『程序 (program)』,這個程序是使用純文字檔,將一些 shell 的語法與命令(含外部命令)寫在里面, 搭配正規表示法、管線命令與數據流重導向等功能,以達到我們所想要的處理目的;
- ? shell script 用在系統管理上面是很好的一項工具,但是用在處理大量數值運算上, 就不夠好了,因為 Shell scripts 的速度較慢,且使用的 CPU 資源較多,造成主機資源的分配不良;
- ? 在 Shell script 的文件中,命令的運行是從上而下、從左而右的分析與運行;
- ? shell script 的運行,至少需要有 r 的權限,若需要直接命令下達,則需要擁有 r 與 x 的權限;
- ? 良好的程序撰寫習慣中,第一行要宣告 shell (#!/bin/bash) ,第二行以后則宣告程序用途、版本、作者等;
- ? 對談式腳本可用 read 命令達成;
- ? 要創建每次運行腳本都有不同結果的數據,可使用 date 命令利用日期達成;
- ? script 的運行若以 source 來運行時,代表在父程序的 bash 內運行之意!
- ? 若需要進行判斷式,可使用 test 或中括號 ( [] ) 來處理;
- ? 在 script 內,$0, $1, $2..., $@ 是有特殊意義的!
- ? 條件判斷式可使用 if...then 來判斷,若是固定變量內容的情況下,可使用 case $var in ... esac 來處理;
- ? 回圈主要分為不定回圈 (while, until) 以及固定回圈 (for) ,配合 do, done 來達成所需任務!
- ? 我們可使用 sh -x script.sh 來進行程序的 debug;
總結
以上是生活随笔為你收集整理的linux-basic(13)学习shell script的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 论坛网站怎么推广(论坛网站怎么推广的)
- 下一篇: 怎么修改织梦调用文章url(织梦相关文章