bash腳本進階

 shell腳本流程控制

    1.if語句

單分支:
if 判斷條件;
 then
? 
雙分支:
if 判斷條件; then
    條件為真的分支代碼
else
    條件為假的分支代碼
fi
 多分支:
if 判斷條件;then
    條件為真的分支代碼
elif 判斷條件;then
    條件為真的分支代碼
elif 判斷條件;then
    條件為真的分支代碼
else
    不符合以上條件的代碼段
fi

例:寫一個腳本/root/bin/argsnum.sh,接受一個文件路徑作為參數;如果參數個數小于1,則提示用戶“至少應該給一個
參數”,并立即退出;如果參數個數不小于1,則顯示第一個參數所指向的文件中的空白行數
#!/bin/bash
if [ $# -lt 1 ];then
        echo "至少輸入一個參數!"
        exit
else
        if [ -f $1 ];then
                echo "$1的空白行數為:`sed -n '/^$/p' $1 | wc -l`"
        else
                echo "你輸入的第一個參數不是文件!"
                exit
        fi
fi

2、case語句

當條件的選擇有多種時,if語句雖然能完成條件判斷,但是代碼不簡潔,這時就可以選用case語句

語法:
case 變量 in
PAT1)
    分支1
    ;;
PAT2)
    分支2
    ;;
PAT3)
    分支3
    ;;
*)
    默認分支
    ;;
esac

case支持glob風格的通配符:
*: 任意長度任意字符
?: 任意單個字符
[]:指定范圍內的任意單個字符
a|b: a或b

例:寫一個腳本/root/bin/yesorno.sh,提示用戶輸入yes或no,并判斷用戶輸入的是yes還是no,或是其它信息
#!/bin/bash
echo -e  "Input yes or no!"
read -s input
input=`echo "$input" | tr 'A-Z' 'a-z'`
case $input in
"yes"|"y")
 echo "The input is yes"
 ;;
"no"|"n")
 echo "The input is no"
 ;;
*)
 echo "$input"
 ;;
esac

3、for循環

for 變量名 in 列表;
    do
        循環體
    done
執行機制:
依次將列表中的元素賦值給“變量名” ; 每次賦值后即執行一次循環體; 直到列表中的元素耗盡,循環結束

例:用for循環打印99乘法表
#!/bin/bash
line=1
for i in `seq 1 9`;
        do
                for k in `seq 1 $i`;
                        do
                         echo -ne "${k}*${i}"="$[$k*$i]\t"
                        done
                 echo 
        done

4、while循環

while CONDITION; 
    do
        循環體
    done
? 
CONDITION:循環控制條件;進入循環之前,先做一次判斷;每一次循環之后會再次做判斷;條件為“ true”,則執行一次循環;
           直到條件測試狀態為“ false”終止循環
 
因此: CONDTION一般應該有循環控制變量;而此變量的值會在循環體不斷地被修正

進入條件: CONDITION為true
退出條件: CONDITION為false

例:while實現打印99乘法表
#!/bin/bash
i=1
while [ $i -le 9 ];
 do
  j=1
  while [ $j -le $i ];
   do
    echo -ne "${j}x${i}=$[$j*$i]\t"
    ((j++))
   done
  echo 
  ((i++))
 done

5、until循環

        until循環和while循環相反,while循環當條件判斷是為真時執行,為假跳出循環。until循環則當條件判斷為假時執行,為真時跳出循環

until CONDITION; 
    do
        循環體
    done
? 
進入條件: CONDITION 為false
退出條件: CONDITION 為true

6、循環控制語句continue和break

continue為跳出這一次循環,continue#為提前結束第#層的本輪循環,而直接進入下一輪判斷;最內層為第1層
break為跳出這一層循環體,break#為結束第n層循環體;最內層為一層

7、創建無限循環

主要運用while和until的特性,使用while true;或者until false使循環體一直運行
一般使用exit和循環控制語句break跳出循環

8、特殊用法

while循環的特殊用法(遍歷文件的每一行):

while read line; 
    do
        循環體
    done < /PATH/FROM/SOMEFILE
依次讀取/PATH/FROM/SOMEFILE文件中的每一行,且將行賦值給變量line

例:掃描/etc/passwd文件每一行,如發現GECOS字段為空,則填充用戶名和單位電話為62985600,并提示該用戶的GECOS信息修改成功。
#!/bin/bash
while read line;
 do
  note=`echo "$line" | cut -d: -f5`
  usr_name=`echo $line | cut -d: -f1`
  [[ -z $note ]] && chfn -h 62985600 -f 62985600 $usr_name &> /dev/null && echo "$usr_name  GECOS 信息修改成功!" 
 done < /etc/passwd

for循環的特殊格式:

for ((控制變量初始化;條件判斷表達式;控制變量的修正表達式))
    do
        循環體
    done
? 
控制變量初始化:僅在運行到循環代碼段時執行一次? 
控制變量的修正表達式:每輪循環結束會先進行控制變量修正運算,而后再做條件判斷

類似C語言語法:
雙小括號方法,即((…))格式,也可以用于算術運算

#I=10
#((I++))

9、select循環

        select循環用來實現shell程序中的交互,能顯示菜單模式的輸出,顯示PS3提示符,等待用戶輸入,

        用戶輸入菜單中的摸個數字,執行相應命令

        用戶輸入被保存在REPLY變量中

select variable in list
    do
        循環體命令
    done

select 是個無限循環,因此要記住用 break 命令退出循環,或用 exit 命令終止腳本。也可以按 ctrl+c退出循環。
select 經常和 case 聯合使用與 for 循環類似,可以省略 in list , 此時使用位置參量

例:輸出UID大于等于1000的用戶,等待用戶輸入菜單選項,輸出對應的用戶的passwd字段
#!/bin/bash

echo "UID大于等于1000的用戶列表:"
select i in `cat /etc/passwd | cut -d: -f1,3 |sort -n -t: -k2 |awk -F: '{if($2>=1000) print $0;}'`;
 do
  name=`echo "$i" | cut -d: -f1`
  grep "^$name:" /etc/passwd 
 done

003.png


shell腳本函數

 介紹: 

        函數function是由若干條shell命令組成的語句塊,實現代碼重用和模塊化編程。
它與shell程序形式上是相似的,不同的是它不是一個單獨的進程,不能獨立運行,而是shell程序的一部分。
函數和shell程序比較相似,區別在于:Shell程序在子Shell中運行而Shell函數在當前Shell中運行。
因此在當前Shell中,函數可以對shell中變量進行修改

函數由兩部分組成:函數名和函數體。

? 
語法一:
function f_name {
...
函數體
...
}
? 
語法二:
f_name() {
...
函數體
...
}

函數的使用:
可在交互式環境下定義函數
可將函數放在腳本文件中作為它的一部分
可放在只包含函數的單獨文件中
函數必須先定義,再調用
 
調用:函數只有被調用才會執行;
調用:給定函數名出現的地方,會被自動替換為函數代碼?
 函數的生命周期:被調用時創建,返回時終止
 
 
函數有兩種返回值:
 
函數的執行結果返回值:
(1) 使用echo或printf命令進行輸出:
(2) 函數體中調用命令的輸出結果
? 
函數的退出狀態碼:
(1) 默認取決于函數中執行的最后一條命令的退出狀態碼
(2) 自定義退出狀態碼, 其格式為:return 從函數中返回,用最后狀態命令決定返回值
return 0 無錯誤返回。
return 1-255 有錯誤返回

函數可以接受參數:

傳遞參數給函數:調用函數時,在函數名后面以空白分隔給定參數列表即可;例如“ testfunc arg1 arg2 ...”
在函數體中當中,可使用$1, $2, ...調用這些參數;還可以使用$@, $*, $#等特殊變量

變量作用域:

環境變量:當前shell和子shell有效
本地變量:只在當前shell進程有效,為執行腳本會啟動專用子shell進程;因此,本地變量的作用范圍是當前shell腳本程序文件,包括腳本中的函數。
局部變量:函數的生命周期;函數結束時變量被自動銷毀
    注意:如果函數中有局部變量,如果其名稱同本地變量, 使用局部變量。
    在函數中定義局部變量的方法
    local NAME=VALUE

函數遞歸:

函數直接或間接調用自身
注意遞歸層數

例:
示例:求5的階層 
fact.sh
#!/bin/bash
#
fact() {
if [ $1 -eq 0 -o $1 -eq 1 ]; then
    echo 1
else
    echo $[$1*$(fact $[$1-1])]
fi

}
fact 5

   


 作業、練習

1、寫一個腳本,用循環顯示三角形

[root@ _161_ ~/bin/8-17_study]# cat dao_san_jiao.sh 
#!/bin/bash
read -t 30 -p "Input num:" num
for i in `seq 1 $num`;
 do
  line=""
  black=$[(2*$i)-1]
  space=$[$num-$i]
  for j in `seq 1 $space`;
   do
    line=$line" "
   done
  
  for k in `seq 1 $black`
   do
    line=$line"*"
   done
  echo "$line"
 done
[root@ _162_ ~/bin/8-17_study]# bash dao_san_jiao.sh
Input num:5
    *
   ***
  *****
 *******
*********

 2、用until循環實現國際象棋棋盤

[root@ _165_ ~/bin/8-17_study]# cat chess_until.sh 
#!/bin/bash
black="\033[47m  \033[0m"
white="\033[40m  \033[0m"
i=1
until [ $i -gt 8 ];
 do
  j=1
  until [ $j -gt 8 ];
   do
    [ $[($i+$j)%2] -eq 0 ] && echo -ne "$white"
    [ $[($i+$j)%2] -ne 0 ] && echo -ne "$black"
    ((j++))
   done
  echo
  ((i++))
 done

004.png

3、寫一個腳本/root/bin/filetype.sh,判斷用戶輸入文件路徑,顯示其文件類型(普通,目錄,鏈接,其它文件類型)

[root@ _177_ ~/bin]# cat 8-15_study/filetype.sh 
#!/bin/bash
read -t 30 -p "Input file!:" filename
echo $filename
[ -z $filename ] && echo "你沒有輸入文件名!" && exit
! [ -a $filename ] &&  echo "你輸入的文件不存在!" && exit

if [ -f $filename ];then
 [ -h $filename ] && echo "$filename is link file!" || echo "$filename is file!"
elif [ -d $filename ];then
 echo "$filename is directory!"
else
 echo "${filename} is other file!"
fi
[root@ _178_ ~/bin]# bash 8-15_study/filetype.sh 
Input file!:e
e
你輸入的文件不存在!
[root@ _179_ ~/bin]# bash 8-15_study/filetype.sh 
Input file!:/etc/issue
/etc/issue
/etc/issue is file!

 4、寫一個腳本/root/bin/checkint.sh,判斷用戶輸入的參數是否為正整數

[root@ _181_ ~/bin]# cat 8-15_study/chkint.sh 
#!/bin/bash
read -t 30 -p "輸入一個數:" num
[[ $num == "0" ]] && echo "你輸入的數為0!" && exit
expr $num + 0 &>/dev/null
if [ $? -eq 0 ];then
 if [ $num -gt 0 ];then
  echo "你輸入的數為正整數!"
 else
  echo "你輸入的數為負整數!"
 fi
else
 echo "你輸入的不是整數!"
fi
[root@ _182_ ~/bin]# bash 8-15_study/chkint.sh
輸入一個數:e
你輸入的不是整數!
[root@ _183_ ~/bin]# bash 8-15_study/chkint.sh
輸入一個數:4.5
你輸入的不是整數!
[root@ _184_ ~/bin]# bash 8-15_study/chkint.sh
輸入一個數:3
你輸入的數為正整數!
[root@ _185_ ~/bin]# bash 8-15_study/chkint.sh
輸入一個數:-2
你輸入的數為負整數!

5、寫一個腳本/root/bin/createuser.sh,實現如下功能:使用一個用戶名做為參數,如果指定參數的用戶存在,就顯
示其存在,否則添加之;顯示添加的用戶的id號等信息

[root@ _186_ ~/bin]# cat 8-15_study/creatuser.sh 
#!/bin/bash
read -t 30 -p "Input username:" username
id $username &>/dev/null
if [ $? -eq 0 ];then
 echo "用戶已存在"
else
 useradd $username
 [ $? -eq 0 ] && id $username && echo -e  "成功創建了\e[32;5m${username}\e[0m用戶" || echo "輸入了非法用戶名!" 
fi
[root@ _187_ ~/bin]# bash 8-15_study/creatuser.sh 
Input username:cej
用戶已存在
[root@ _188_ ~/bin]# bash 8-15_study/creatuser.sh 
Input username:cej2    
uid=1008(cej2) gid=1008(cej2) 組=1008(cej2)
成功創建了cej2用戶

6、判斷/var/目錄下所有文件的類型

[root@ _191_ ~/bin]# cat for_script/var_type_pwd.sh 
#!/bin/bash
cd /var
for i in `ls -A /var`;
 do
  echo "$i is `file -b $i`" 
 done
[root@ _192_ ~/bin]# bash for_script/var_type_pwd.sh 
account is directory
adm is directory
cache is directory
crash is directory
db is directory
empty is directory
games is directory
gopher is directory
kerberos is directory
lib is directory
local is directory
lock is symbolic link to `../run/lock'
log is directory
mail is symbolic link to `spool/mail'
nis is directory
opt is directory
preserve is directory
run is symbolic link to `../run'
spool is directory
tmp is sticky directory
.updated is ASCII text
www is directory
yp is directory

7、添加10個用戶user1-user10,密碼同用戶名

[root@ _196_ ~/bin/for_script]# cat user_add_1_10.sh 
#!/bin/bash
for i in `seq 1 10`;
 do
  id user$i &>/dev/null
  if [ $? -eq 0 ];then
   echo "user$i exist!"
  else
   useradd user$i
   echo "user$i" | passwd --stdin user$i &>/dev/null
   [ $? -eq 0 ] && echo "user$i create successful!" || echo "user$i create faild !" 
  fi
 done
[root@ _197_ ~/bin/for_script]# bash user_add_1_10.sh 
user1 create successful!
user2 create successful!
user3 create successful!
user4 create successful!
user5 create successful!
user6 create successful!
user7 create successful!
user8 create successful!
user9 create successful!
user10 create successful!

8、、 /etc/rc.d/rc3.d目錄下分別有多個以K開頭和以S開頭的文件;分別讀取每個文件,以K開頭的文件輸出為文件加stop
,以S開頭的文件輸出為文件名加start;“ K34filename stop” “S66filename start”

[root@ _200_ ~/bin/for_script]# cat K_S_Find.sh 
#!/bin/bash
K_num=0
S_num=0
cd /etc/rc.d/rc3.d
for i in `ls -A /etc/rc.d/rc3.d`;
 do
  if echo "$i" | grep  -q "^K";then
   ((K_num++))
   echo "$i stop"
  elif echo "$i" | grep  -q "^S";then
   ((S_num++))
   echo "$i start"
  else
   echo "$i"   
  fi
 done
echo "K:$K_num"
echo "S:$S_num"
[root@ _201_ ~/bin/for_script]# bash K_S_Find.sh 
K50netconsole stop
S10network start
K:1
S:1

 

 9、寫一個腳本,提示輸入正整數n的值,計算1+2+3+…n的總和

[root@ _206_ ~/bin/for_script]# cat int_sum.sh 
#!/bin/bash
read -t 30 -p "Input int:" int_num
expr $int_num + 0 &>/dev/null
! [ $? -eq 0 ] && { echo "你輸入了非數字或者零!";exit; }     #判斷是否是整數
! [ $int_num -gt 0 ] && { echo "你輸入的不是正數!" ;exit; }   #判斷是否是正數
sum=0
for i in `seq 1 $int_num`;
 do
  let sum=${sum}+$i
 done
echo "sum is $sum"
[root@ _207_ ~/bin/for_script]# bash int_sum.sh 
Input int:100
sum is 5050

10、寫一個腳本,提示請輸入網絡地址,如192.168.0.0,判斷輸入的網段中主機在線狀態

[root@ _209_ ~/bin/for_script]# cat ping_for.sh 
#!/bin/bash
for i in `seq 76 99`;
 do
  ping -c 1 -w1 10.1.252.$i &>/dev/null
  if [ $? -eq 0 ];then
   echo -e "\033[33m10.1.0.$i is online!\033[0m"
  else
   echo  "10.1.0.$i is offline!"
  fi
 done
[root@ _210_ ~/bin/for_script]# bash ping_for.sh
10.1.0.76 is offline!
10.1.0.77 is online!
10.1.0.78 is offline!
10.1.0.79 is offline!
10.1.0.80 is offline!
10.1.0.81 is offline
...

 待續!

 

原創文章,作者:M20-1--孔祥文,如若轉載,請注明出處:http://www.www58058.com/38002

(0)
M20-1--孔祥文M20-1--孔祥文
上一篇 2016-08-21
下一篇 2016-08-21

相關推薦

  • 常用的MySQL數據庫備份

    常用的MySQL數據庫備份方式 前言 為什么需要備份數據? 數據的備份類型 MySQL備份數據的方式 備份需要考慮的問題 設計合適的備份策略 實戰演練 使用cp進行備份 使用mysqldump+復制BINARY LOG備份 使用lvm2快照備份數據 使用Xtrabackup備份 總結 前言 我們試著想一想, 在生產環境中什么最重要?如果我們服務器的硬件壞了可…

    2016-10-01
  • N25第五周博客作業

    第五周博客作業   1、顯示/boot/grub/grub.conf中以至少一個空白字符開頭的行;   2、顯示/etc/rc.d/rc.sysinit文件中以#開頭,后面跟至少一個空白字符,而后又有至少一個非空白字符的行;   3、打出netstat -tan命令執行結果中以‘LISTEN’,后或跟空白字符結尾的行; &nbs…

    Linux干貨 2016-12-28
  • bash代碼注入的安全漏洞

           很多人或許對上半年發生的安全問題“心臟流血”(Heartbleed Bug)事件記憶頗深,這兩天,又出現了另外一個“毀滅級”的漏洞——Bash軟件安全漏洞。這個漏洞由法國GNU/Linux愛好者Stéphane Chazelas所發現。隨后,美國電腦緊急應變中心(US-CERT)、紅帽以及多家從事安全的公…

    Linux干貨 2015-03-30
  • nginx學習筆記

    深入理解Nginx 一、Nginx是什么? 二、為什么選擇Linux ? 三、Nginx生成的文件有哪些? 四、Nginx的配置詳解? 五、模塊功能詳解 六、虛擬主機配置詳解?                 一、Nginx是什么? Nginx(engine X)是一個高性能的H…

    Linux干貨 2017-03-15
  • 馬哥教育網絡班21期第六周作業

    詳細總結VIM編輯器的使用并完成以下練習題 1、復制/etc/rc.d/rc.sysinit文件至/tmp目錄,將/tmp/rc.sysinit文件中的以至少一個空白字符開頭的行的行首加# cp /etc/rc.d/rc.sysinit /tmp vim /tmp/rc.sysinit :%s/^[[:space:]]\+/#/…

    Linux干貨 2016-08-22
  • Linux之iptables原理詳解

    目錄: 一、netfilter與iptables 二、filter、nat、mangle等規則表 三、INPUT、FORWARD等規則鏈和規則 四、Linux數據包路由原理 五、iptables編寫規則  一、netfilter與iptables (1)Netfilter是由Rusty Russell提出的Linux 2.4內核防火墻框架,該框架既…

    2017-08-04

評論列表(1條)

  • 馬哥教育
    馬哥教育 2016-08-22 09:19

    文章對選擇語句和循環語句的語法總結的很詳細,同時也通過相應的示例加深了自己對腳本的理解,腳本的學習沒有什么捷徑??科匠5姆e累,平時寫的多了,看的多了,我們才能運用自如,我們可以在平時的寫作中嘗試用不同的語法總結出他們的不同點和最適用的場景哦。

欧美性久久久久