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 20:46
下一篇 2016-08-21 20:46

相關推薦

  • Linux之Centos系統的啟動流程詳述

    概述 了解系統的啟動流程,有助于我們了解Linux系統上的一些工作原理,有助于我們深入的理解一個系統的運作方式,那么本篇就以CentOS6系統為例,介紹一下有關Linux系統啟動相關的內容,分為一下幾個部分 1、Linux系統的一些基礎概念 2、CentOS6上的啟動流程概述 第一章 Linux系統的一些基礎概念 Linux系統的組成部分:內核(kernel…

    Linux干貨 2016-09-29
  • 初識Linux-即使是997也不能停止學習

    1.計算機的組成及其功能:    從1946年第一臺通用計算機ENIAC誕生至今,幾乎所有的計算機系統都是建立在馮諾依曼體系結構上的。那么何為馮諾依曼體系結構? 馮諾依曼體系結構:        控制器:是整個計算機的中樞,負責計算機的整體調度工作,將指令從存儲器中取出,并對指令進行解釋執行。 &n…

    Linux干貨 2016-10-29
  • 計算機與操作系統

    計算機系統=Hardware+Software Linux操作系統=GNU/kernel+程序 (user space) ————– apps   shell    (人機交互接口) lib call(半層)  (kernel space) —&#…

    Linux干貨 2017-02-14
  • 安裝RPM包 rpm與yum工具的使用

    1.認識yum與rpm工具.                 在windows下安裝一個軟件很輕松,只要雙擊.exe的文件,安裝提示連續 “下一步” 即可,然而linux系統下安裝一個軟件似乎并不那么輕松了,因為我們不是在圖形界面下。所以你要學會如何在linux下安裝一…

    Linux干貨 2016-08-26
  • ansible高級應用

    上一篇博客介紹了ansible的基礎應用Modules,博客地址 http://www.www58058.com/14860 。這次介紹下Ansible的另一個核心模塊Playbooks。   Ansible的核心模塊:     Ansible core:   &nbs…

    Linux干貨 2016-04-18
  • 磁盤管理,軟raid,腳本基礎

    1、創建一個10G分區,并格式為ext4文件系統; (1) 要求其block大小為2048, 預留空間百分比為2, 卷標為MYDATA, 默認掛載屬性包含acl; mke2fs -t ext4 -L MYDATA -m 2 /dev/sdb tune2fs -o acl /dev/sdb (2) 掛載至/data/mydata目錄,要求掛載時禁止程序自動運行…

    Linux干貨 2017-10-25

評論列表(1條)

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

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

欧美性久久久久