<code>Bash程式設計之循環&函數</code>
<code>一、bash循環(</code><code>for</code><code>,</code><code>while</code><code>,until)</code>
<code>二、測試腳本</code>
<code>三、多分支</code><code>if</code>
<code>四、</code><code>case</code><code>語句的文法格式</code>
<code>五、function函數</code>
<code>六、變量作用域</code>
<code>七、函數遞歸</code>
一、bash循環(for,while,until)
1.bash腳本程式設計
順序執行
選擇執行
循環執行
for,while,until,
進入條件:
for :清單元素非空
while :條件測試結果為“真”
until:條件測試結果為“假”
退出條件:
for:清單元素為空
while:條件測試結果為“假”
until:條件測試結果為“真”
2.循環控制語句:
while CONDATION1 ; do
CMD1
...
if CONDATION2;then
continue //結束本次循環
fi
CMDn
...
done
示例:求100以内所有偶數之和
3.建立循環體;
while true ;do
循環體
退出方式:某個測試條件滿足時,讓循環體執行break指令
break:直接跳出循環
continue:直接進入下一次循環
sleep 數字[時間機關] //預設是s,d:天,h:小時
4.while循環的特殊用法(周遊檔案的行)
while read VAR; don
done < /path/to/somefile
依次讀取/path/from/somefile檔案中的每一行,且将某指派給VAR變量
示例:腳本5
5.for循環的特殊用法
for ((控制變量初始化;條件判斷表達式;控制var的修正語句))
循環體
done
控制變量初始化,僅在循環代碼開始運作時執行一次
控制變量的修正語句;每輪循環結束會先進行控制變量修正運算,而後在根據判斷條件判斷
二、測試腳本
腳本1:求even:偶數,odd:奇數,100以内之和
<code> </code><code>#!/bin/bash</code>
<code> </code><code>declare -i evensum=0 /</code>
<code> </code><code>declare -i i=0</code>
<code> </code><code>while</code> <code>[ $i -le 100 ] ; </code><code>do</code>
<code> </code><code>let</code> <code>i++ </code><code>//前面不能用let $i++</code>
<code> </code><code>if</code> <code>[ $[$i%2] -eq 0 ] ;then </code><code>//此處隻能使用[ ] 進行引用</code>
<code> </code><code>let</code> <code>evensum+=$i</code>
<code> </code><code>else</code>
<code> </code><code>continue</code>
<code> </code><code>fi</code>
<code> </code><code>done</code>
<code> </code><code>echo </code><code>"Even sum is $evensum"</code>
//求所有奇數之和2500
<code> </code><code>declare -i evensum=0</code>
<code> </code>
<code> </code><code>while</code> <code>[ $i -lt 100 ] ; </code><code>do</code> <code>//必須是小于100,否則會出錯</code>
<code> </code><code>let</code> <code>i++</code>
<code> </code><code>if</code> <code>[ $[$i%2] -eq 1 ] ;then</code>
<code> </code><code>let</code> <code>evensum+=$i</code>
<code> </code><code>else</code>
<code> </code><code>continue</code>
<code> </code><code>fi</code>
腳本2:求和,break方式實作
<code> </code><code>#!/bin/bashk</code>
<code> </code><code>declare -i oddsum=0</code>
<code> </code><code>declare -i i=1</code>
<code> </code><code>while</code> <code>true</code><code>; </code><code>do</code>
<code> </code><code>let</code> <code>oddsum+=$i</code>
<code> </code><code>let</code> <code>i+=2</code>
<code> </code><code>if</code> <code>[ $i -gt 100 ];then</code>
<code> </code><code>echo $oddsum</code>
<code> </code><code>break</code>
腳本3:每個三s擷取已經登入的使用者資訊,如果wolf使用者已經登入,則記錄于日志中,并退出
<code> </code><code>if</code> <code>who |grep wolf &> /dev/</code><code>null</code> <code>; then</code>
<code> </code><code>sleep 3</code>
<code> </code><code>echo </code><code>"$(date +%F-%H-%M) wolf loggin..."</code> <code>>> /tmp/userlog.log</code>
腳本4:util實作腳本3
<code> </code><code>until who | grep </code><code>"wolf"</code> <code>&> /dev/</code><code>null</code> <code>; </code><code>do</code>
<code> </code><code>sleep 3</code>
腳本5:目前os上id号為偶數的使用者及其shell
<code> </code><code>declare -i userid</code>
<code> </code><code>while</code> <code>read i ;</code><code>do</code>
<code> </code><code>userid=`echo $i | cut -d: -f3`</code>
<code> </code><code>//注:同上userid=$(echo $i | cut -d: -f3)</code>
<code> </code><code>if</code> <code>[ $[$userid%2] -eq 0 ] ;then</code>
<code> </code><code>echo $i | cut -d: -f1,7</code>
<code> </code><code>done < /etc/passwd</code>
<code> </code><code>//另一種實作方式,while循環 </code>
<code> </code><code>userid=$(echo $i | cut -d: -f3)</code>
<code> </code><code>username=$(echo $i | cut -d: -f1)</code>
<code> </code><code>usershell=$(echo $i | cut -d: -f7)</code>
<code> </code><code>if</code> <code>[ $[$userid%2] -eq 0 ] ;then</code>
<code> </code><code>echo </code><code>"$username $userid $usershell"</code>
<code> </code><code>done < /etc/passwd</code>
腳本6:for的特殊用法
<code> </code><code>declare -i sum=0</code>
<code> </code><code>for</code> <code>((i=1;i<=100;i++));</code><code>do</code>
<code> </code><code>let</code> <code>sum+=$i</code>
<code> </code><code>echo </code><code>"Sum: is .$sum"</code>
腳本7;使用for的特殊用法,列印99表
<code> </code><code>#</code>
<code> </code><code>for</code> <code>((i=1;i<=9;i++));</code><code>do</code>
<code> </code><code>for</code> <code>((j=1;j<=i;j++));</code><code>do</code>
<code> </code><code>echo -e -n </code><code>"${i}*${j}=$[$i*$j]\t"</code>
<code> </code><code>done</code>
<code> </code><code>echo </code><code>//這個echo用于換行,因為前面不換行了</code>
三、多分支if
多分支if
if condation1;then
..
elif
...
else
fi
單分支if
示例1:顯示一個菜單給使用者
要求:
1.提示使用者給出自己的選擇
2.正确的選擇,則給出相應的資訊,否則提示,使用者重新選擇
<code> </code><code>cat << EOF</code>
<code> </code><code>cpu) display cpu information</code>
<code> </code><code>mem) display memory information</code>
<code> </code><code>disk) display disks information</code>
<code> </code><code>quit) quit</code>
<code> </code><code>===============================</code>
<code> </code><code>EOF</code>
<code> </code><code>read -p </code><code>"Enter your choice: "</code> <code>opt</code>
<code> </code><code>while</code> <code>[ </code><code>"$opt"</code> <code>!= </code><code>"cpu"</code> <code>-a </code><code>"$opt"</code> <code>!= </code><code>"mem"</code> <code>-a </code><code>"$opt"</code> <code>!= </code><code>"disk"</code> <code>-a </code><code>"$opt"</code> <code>!= </code><code>"disk"</code> <code>-a "$</code>
<code> </code><code>opt</code><code>" != "</code><code>quit</code><code>" ] ;do read -p "</code><code>Enter your choice: " opt</code>
<code> </code><code>if</code> <code>[ </code><code>"$opt"</code> <code>== </code><code>"cpu"</code> <code>] ;then</code>
<code> </code><code>lscpu</code>
<code> </code><code>elif [ </code><code>"$opt"</code> <code>== </code><code>"mem"</code> <code>] ;then</code>
<code> </code><code>free -m</code>
<code> </code><code>elif [ </code><code>"$opt"</code> <code>== </code><code>"disk"</code> <code>] ;then</code>
<code> </code><code>fdisk -l /dev/sd[a-z] </code>
<code> </code><code>else</code>
<code> </code><code>echo </code><code>"quit"</code>
<code> </code><code>exit 0</code>
<code> </code><code>fi</code>
四、case語句的文法格式
case $VAR in //僅僅支援glob風格的通配符
PAT1)
;; //雙分号結尾
PAT2)
;; //
...
*)
;;
esac
注意:
case支援glob風格的通配符
*:任意長度的任意字元
?:任意單個字元
[]:範圍内的
a|b :a或者b
case實作示例
<code> </code><code>case</code> <code>$opt </code><code>in</code>
<code> </code><code>cpu) </code><code>//不用加“ ”</code>
<code> </code><code>;; </code><code>//最後要加 ;;</code>
<code> </code><code>disk)</code>
<code> </code><code>fdisk -l /dev/sd[a-z]</code>
<code> </code><code>;;</code>
<code> </code><code>mem)</code>
<code> </code><code>*)</code>
<code> </code><code>exit 0 ;;</code>
<code> </code><code>esac</code>
五、function函數
過程式程式設計:代碼重用
子產品化程式設計
結構化程式設計
把一段獨立功能的代碼當做一個整體,并為之一個名字;命名的代碼段,此即為函數
注意:定義函數的代碼段不會自動執行,在調用時執行,所謂調用函數,在代碼中給定函數名即可
函數名出現的任何位置,在代碼執行時,都會被自動替換為函數代碼
文法一:
function f_name () { //function和f_name之間有空格
...函數體...
}
文法二:
f_name() { //f_name() 中間沒有空格
...函數體...
函數的生命周期:每次被調用時,傳回時終止
其狀态傳回結果:函數體中運作的最後一條指令的狀态結果;
自定義狀态傳回值:需要使用:return
return [0-255]
0:成功
1-255:失敗
腳本使用:exit #作為其傳回值
示例:腳本4
注意:在函數中,不能使用$1,$2,...因為具有特殊的意義
因為函數也可以接受參數,
$1,$2調用的是,傳遞給函數的參數,而不是腳本的參數
函數傳回值
函數的執行結果傳回值;
(1)使用echo或printf指令進行輸出
printf不會自動換行,相當于echo -n
(2)函數體中調用的指令的執行結果
函數的退出狀态碼
1.預設取決于函數最後執行的那一條指令
2.自定義的方法,return
函數可以接受參數
傳遞參數給函數
1.在函數體中,可以使用$1,$2,...引用傳遞給函數的參數;
$*和$@調用所有參數,
$#引用參數個數
2.在調用函數時,在函數名後以空白字元分隔給定參數清單即可,例如:a b c d
六、變量作用域
局部變量:作用域是函數的聲明周期
定義:locale VARIABLE=VALUE
本地變量:作用域是運作腳本的shell的生命周期;作用範圍是目前shell程式
a=VALUE //
全局變量:
環境變量:
全局變量和局部變量對比:
<code> </code><code>#!/bin/bash</code>
<code> </code><code>name=tom</code>
<code> </code><code>setname() {</code>
<code> </code><code>local name=jerry</code>
<code> </code><code>echo </code><code>"Function name:$name"</code>
<code> </code><code>}</code>
<code> </code><code>setname</code>
<code> </code><code>echo </code><code>"Shell: $name"</code>
<code> </code><code>[root@localhost ~]# bash 2.sh</code>
<code> </code><code>Function name:jerry</code>
<code> </code><code>Shell: tom</code>
七、函數遞歸 //自己調用自己
函數間接或者直接就調用自身
10!=10*9!=10*9*8!=...
<code>#!/bin/bash</code>
<code>fact() {</code>
<code> </code><code>if</code> <code>[ $1 -eq 0 -o $1 -eq 1 ] ;then </code><code>//[ $1 -eq 0 ] || [ $1 -eq 1 ] 這樣也可以</code>
<code> </code><code>echo $1</code>
<code> </code><code>echo $[$1*$(fact $[$1-1])]</code>
<code>}</code>
<code>fact $1</code>
<code>fab() {</code>
<code> </code><code>if</code> <code>[ $1 -eq 1 ] ;then</code>
<code> </code><code>echo -n </code><code>"1 "</code>
<code> </code><code>elif [ $1 -eq 2 ] ;then</code>
<code> </code><code>echo -n </code><code>"1 "</code>
<code> </code><code>echo -n </code><code>"$[$(fab $[$1-1]+$(fab $[$1-2])]"</code>
<code>} </code>
<code>for</code> <code>i </code><code>in</code> <code>$(seq 1 $1) ;</code><code>do</code>
<code> </code><code>fab $i</code>
<code>done</code>
<code>echo</code>
服務啟動服務架構
$lockfile,值/var/lock/subsys/SCRIPT_NAME
1.可以接受的參數start,stop,restart,status四個參數
2.如果參數非此四個,則顯示幫助後退出
3.start,建立lockfile,并顯示啟動:stop,則建立lockfile,并顯示停止;restart,則先删除此檔案,再建立此檔案,而後顯示重新開機完成,;
statue根據lockfile是否存在,顯示running/stopped
注:務必使用case語句
<code>#</code>
<code># chkconfig: - 50 50</code>
<code># description test_service_script</code>
<code>prog=$(basename $0)</code>
<code>lockfile=/</code><code>var</code><code>/</code><code>lock</code><code>/subsys/$prog</code>
<code>case</code> <code>$1 </code><code>in</code>
<code>start)</code>
<code> </code><code>if</code> <code>[ -f $lockfile ] ;then</code>
<code> </code><code>echo </code><code>"$prog is running yet."</code>
<code> </code><code>touch $lockfile </code>
<code> </code><code>[ $? -eq 0 ] && echo </code><code>"Start $prog finished.."</code>
<code> </code><code>;;</code>
<code>stop)</code>
<code> </code><code>rm -f $lockfile</code>
<code> </code><code>[ $? -eq 0 ] && echo </code><code>"$prog stopped.."</code>
<code> </code><code>echo </code><code>"$prog is not running.."</code>
<code>restart)</code>
<code> </code><code>if</code> <code>[ -f $lockfile ] ; then </code>
<code> </code><code>touch $lockfile</code>
<code> </code><code>echo </code><code>"$prog restart finished.."</code>
<code> </code><code>echo </code><code>"$prog start finished.."</code>
<code>status)</code>
<code> </code><code>echo </code><code>"$prog is running.."</code>
<code> </code><code>echo </code><code>"$prog is stopped.."</code>
<code>*)</code>
<code> </code><code>echo </code><code>"Usage: $prog {start|stop|resatrt|status}"</code>
<code>esac </code>
<code> </code><code>cp service /etc/init.d/service</code>
<code> </code><code>chmod +w /etc/init.d/service</code>
<code> </code><code>chkconfig --add service</code>
<code> </code><code>service service start</code>
八、function腳本
1.給定一個使用者名,擷取其id和shell
<code> </code><code>userinfo() {</code>
<code> </code><code>if</code> <code>id </code><code>"$username"</code> <code>&> /dev/</code><code>null</code> <code>;then </code>
<code> </code><code>grep </code><code>"$username"</code> <code>/etc/passwd | cut -d: -f3,7</code>
<code> </code><code>else</code>
<code> </code><code>echo </code><code>"No $username such user.."</code>
<code> </code><code>}</code>
<code> </code><code>username=$1</code>
<code> </code><code>userinfo </code><code>//調用該函數,可以調用多次</code>
<code> </code><code>username=$2</code>
<code> </code><code>userinfo</code>
2.更新版
<code> </code><code># chkconfig: - 50 50</code>
<code> </code><code># description test_service_script</code>
<code> </code><code>prog=$(basename $0)</code>
<code> </code><code>lockfile=/</code><code>var</code><code>/</code><code>lock</code><code>/subsys/$prog</code>
<code> </code><code>start() {</code>
<code> </code><code>if</code> <code>[ -f $lockfile ] ;then</code>
<code> </code><code>echo </code><code>"$prog is running yet."</code>
<code> </code><code>touch $lockfile </code>
<code> </code><code>[ $? -eq 0 ] && echo </code><code>"Start $prog finished.."</code>
<code> </code><code>stop() {</code>
<code> </code><code>rm -f $lockfile</code>
<code> </code><code>[ $? -eq 0 ] && echo </code><code>"$prog stopped.."</code>
<code> </code><code>echo </code><code>"$prog is not running.."</code>
<code> </code><code>restart() {</code>
<code> </code><code>if</code> <code>[ -f $lockfile ] ; then </code>
<code> </code><code>touch $lockfile</code>
<code> </code><code>echo </code><code>"$prog restart finished.."</code>
<code> </code><code>echo </code><code>"$prog start finished.."</code>
<code> </code><code>status() {</code>
<code> </code><code>echo </code><code>"$prog is running.."</code>
<code> </code><code>echo </code><code>"$prog is stopped.."</code>
<code> </code><code>usage() {</code>
<code> </code><code>echo </code><code>"Usage: $prog {start|stop|resatrt|status}"</code>
<code> </code><code>case</code> <code>$1 </code><code>in</code>
<code> </code><code>start)</code>
<code> </code><code>start ;;</code>
<code> </code><code>stop)</code>
<code> </code><code>stop ;;</code>
<code> </code><code>restart)</code>
<code> </code><code>restart;;</code>
<code> </code><code>status)</code>
<code> </code><code>status;;</code>
<code> </code><code>usage;;</code>
3.添加10個使用者
添加使用者的功能用函數實作,使用者名作為參數傳遞給函數
<code># 5: user is exists</code>
<code>adduser() {</code>
<code> </code><code>if</code> <code>id $1 &> /dev/</code><code>null</code><code>; then</code>
<code> </code><code>return</code> <code>5</code>
<code> </code><code>useradd $1</code>
<code> </code><code>retval=$?</code>
<code> </code><code>return</code> <code>$retval </code>
<code>for</code> <code>i </code><code>in</code> <code>{1..10} ;</code><code>do</code>
<code> </code><code>adduser ${1}$i </code>
<code> </code><code>a=$? </code><code>//$?不要直接引用,如果需要多次引用的話,進行指派變量</code>
<code> </code><code>if</code> <code>[ $a -eq 0 ] ;then</code>
<code> </code><code>echo </code><code>"useradd succeed..."</code>
<code> </code><code>elif [ $a -eq 5 ] ;then</code>
<code> </code><code>echo </code><code>"user ${1}$i is exists ,useradd failure."</code>
<code> </code><code>echo </code><code>"Unknown errors.."</code>
<code></code>
本文轉自MT_IT51CTO部落格,原文連結:http://blog.51cto.com/hmtk520/1979188,如需轉載請自行聯系原作者