shell腳本練習

這篇文章主要介紹shell編程的實例

一、邏輯判斷之if語句

1.判斷年齡?

[root@centos7 9_1 ]#cat  iftest.sh 
#!/bin/bash
read -p "Please input  your age:" age     
## 判斷用戶輸入的必須是數字
if [[ "$age" =~ ^[0-9]+$ ]];then
    true
else
    echo "Please input digit"
    exit 10
fi
## 判斷用戶的年齡,並輸出相應的信息
if [ "$age" -ge 0 -a $age -le 18 ];then             
    echo "good good study,day day up"
elif [ "$age" -gt 18 -a $age -le 60 ];then    
## 由於前面已經判斷爲數字,並且爲正整數,所以的 "$age" -gt 18 可以省略;

    echo "work hard"
elif [ "$age" -gt 60 -a $age -le 120 ];then   
## 同理,這裏的"$age" -gt 60也可以省略,優化
    echo "enjoy your life"
else 
    echo "you don not come from the earch"
fi

2.如何判斷yes或no?

思路1:
1.用戶輸入的所有選擇:y|yes|Y|YES,同n|no|N|NO
2.統一判斷爲大寫或者小寫:tr進行轉換
3.使用兩種選擇判斷:2:使用正則匹配y|yes;n|no或者大寫

#!/bin/bash
read  -p "Input yes or no:" answer
ans=`echo "$answer"|tr 'A-Z' 'a-z'`

if [ "$ans" = "yes" -o "$ans" = "y" ];then
        echo "YES"
elif [ "$ans" = "no" -o "$ans" = "n" ];then
        echo "NO"
else
        echo "Please input yes or no"
fi

思路2:使用正則進行判斷

#!/bin/bash
read  -p "Input yes or no:" answer
if [[ "$answer" =~ ^[Yy]([Ee][Ss])?$ ]];then
        echo YES
elif [[ "$answer" =~ ^[Nn][Oo]?$ ]];then
        echo "NO"
else
        echo "Please input yes or no"
fi

4.判斷是否富有或帥氣?

[root@centos7 9_1 ]#vim yesorno2.sh
#!/bin/bash
read -p "Are you rich? yes or no: " answer
if [[ "$answer" =~ ^[Yy]([Ee][Ss])?$ ]];then
        echo OK
elif [[ "$answer" =~ ^[Nn][Oo]?$ ]];then
        read -p "Are you handsome? yes or no: " answer
        if [[ "$answer" =~ ^[Yy]([Ee][Ss])?$ ]];then
                echo Ok
                exit
        elif [[ "$answer" =~ ^[Nn][Oo]?$ ]];then
                echo "work hard"
        else
                echo "Please input yes or no"
        fi
else
        echo "Please input yes or no"
fi

二、邏輯判斷之case語句

1.判斷數字

[root@centos7 9_1 ]#vim casetest.sh
#!/bin/bash

read -p "Please input a digit: " num
case $num in
1|2|3)
        echo 1,2,3
        ;;
4|5|6)
        echo 4,5,6
        ;;
7|8|9)
        echo 7,8,9
        ;;
*)
        echo other digit
        ;;
esac

2.判斷yes|no

#!/bin/bash
read -p "Please input yes or no: " ans
case $ans in
[Yy]|[Yy][Ee][Ss])
    echo YES
    ;;
[Nn]|[Nn][Oo])
    echo NO
    ;;
*)  
    echo input false
    ;;
esac

3.打印菜單:

[root@CentOS6 ~ ]#cat menu.sh 
#!/bin/bash

cat <<EOF
1:lamian
2:huimian
3:daoxiaomian
4:junbing
5:mifan
EOF

read -p "Please choose the number: " num
case $num in 
1) 
    echo "lamian price is 15"
    ;;
2)
    echo "huimian price is 18"
    ;;
3)  
    echo "daoxiaomian price is 13"
    ;;
4)  
    echo "junbing price is 10"
    ;;
5)
    echo "mifan price is 2"
    ;;
*)
    echo "INPUT false"
esac

效果:
[root@CentOS6 ~ ]#sh menu.sh 
1:lamian
2:huimian
3:daoxiaomian
4:junbing
5:mifan
Please choose the number: 5
mifan price is 2

三、循環之for循環

help for————兩種語法
語法1:
for NAME [in WORDS ... ] ; do COMMANDS; done
語法2:
for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done

[root@centos7 9_2 ]#for num in 1 2 3 4 5;do echo "num=$num"; done
num=1
num=2
num=3
num=4
num=5

1.不斷追加求和

[root@centos7 9_2 ]#sum=0; for num in 1 2 3 4 5; do sum=$[sum+num];done ;echo sum=$sum
sum=15

2.求1+2+3+..+100的和 (面試題)

方法1:    {1..100}生成序列
[root@centos7 9_2 ]#sum=0; for num in {1..100}; do sum=$[sum+num];done ;echo sum=$sum
sum=5050
## 用於計算的方式有$[] 和$(())以及let等等。

方法2:seq 100生成序列
[root@centos7 9_2 ]#sum=0; for num in `seq 100`; do sum=$[sum+num];done ;echo sum=$sum
sum=5050

2.1 求1+2+3+..+100以內所有奇數的和|所有偶數的和?

奇數之和:

[root@centos7 ~ ]#sum=0; for num in {1..100..2}; do sum=$[sum+num];done ;echo sum=$sum
sum=2500
[root@centos7 ~ ]#sum=0; for num in `seq 1 2 100`; do sum=$[sum+num];done ;echo sum=$sum
sum=2500

偶數之和:

[root@centos7 ~ ]#sum=0; for num in {2..100..2}; do sum=$[sum+num];done ;echo sum=$sum
sum=2550
[root@centos7 ~ ]#sum=0; for num in `seq 2  2 100`; do sum=$[sum+num];done ;echo sum=$sum
sum=2550

2.2 打印奇數和偶數的幾種方法?

[root@centos7 9_2 ]#seq 1 2 10————打印奇數
1
3
5
7
9
[root@centos7 9_2 ]#seq 2 2 10————打印偶數
2
4
6
8
10
[root@centos7 9_2 ]#seq 1 10 |sed -n "1~2p" ——————sed打印奇數
1
3
5
7
9
[root@centos7 9_2 ]#seq 1 10 |sed -n "2~2p"————————sed打印偶數
2
4
6
8
10
[root@centos7 ~ ]#echo {1..10..2}   ————————————————{}也可以實現輸出奇數
1 3 5 7 9
[root@centos7 ~ ]#echo {2..10..2}   ————————————————{}打印偶數
2 4 6 8 10

3.練習:如何實現批量執行一個目錄下的所有腳本?————(前提:所有文件都擁有x權限,並且是非交互式的)

[root@centos7 9_2 ]#ls
case_yesorno.sh  test.sh
[root@centos7 9_2 ]#
[root@centos7 9_2 ]#for filename in *.sh;do ./$filename;done
Please input yes or no: yes
YES
hello,world

4.練習:批量創建user1..10的用戶,並設置密碼爲magedu,設置首次登錄更改密碼?

[root@centos7 9_2 ]#vim createuser_n.sh 
#!/bin/bash
for num in {1..10};do
         useradd user${num} 
         echo "magedu" |passwd --stdin user${num} &> /dev/null
         passwd -e user${num} &> /dev/null
done

5.練習:編寫一個×××掃描器,實現掃描一個網段(1-254)中那些主機是開機的?

## 默認是順序執行,ping完一個ip後再ping下一個,那麼可不可以並行執行?
[root@centos7 9_2 ]#cat scanip.sh 
#!/bin/bash
## 每次執行前清空文件
> /data/iplist.log                                  
net=172.20.129
for i in {1..254};do
## 添加{}實現並行執行
    { if ping -c1 -W1 $net.$i &> /dev/null ;then    
        echo $net.$i is up
        echo $net.$i >> /data/iplist.log            ## 注意這裏是追加,所以在腳本開始清空文件
    else
        echo $net.$i is down
    fi } &                                          ## 前後對應,並放入後臺執行
done
wait                                                ## 由於需要手動按enter退出,所以添加wait命令自動退出

優化版:交互式輸入
[root@centos7 9_2 ]#vim scanip.sh 
#!/bin/bash
> /data/iplist.log
## 交互式輸入
read -p "Please input the network:(eg:192.168.0.0):" net 
## 截取前三段,否則出現1.1.1.0.249情況
net=`echo $net|cut -d. -f1-3`                               
for i in {1..254};do
        { if ping -c1 -W1 $net.$i &> /dev/null ;then
                echo $net.$i is up
                echo $net.$i >> /data/iplist.log
        else
                echo $net.$i is down
        fi } &
done
wait

6.練習:寫一個計算網絡ID的netid.sh,ip地址和子網掩碼做與運算,如下所示:

[root@centos7 9_2 ]#echo $[193&240]
192

[root@centos7 9_2 ]#cat netid.sh 
#!/bin/bash
read -p "input a ip: " ip                   
read -p "input a netmask: " netmask     
## 每次cut取一個字段,然後循環4次    
for i in {1..4};do                      
    net=`echo $ip |cut -d. -f$i`
    mask=`echo $netmask |cut -d. -f$i`
    if [ $i -eq 1 ];then    
## 先一個字段與另外一個字段相與,最後再進行組合           
        netid=$[net&mask]                   
    else                
        netid=$netid.$[net&mask]
    fi
done
echo netid=$netid

優化版:
[root@centos7 9_2 ]#cat netid.sh 
#!/bin/bash
read -p "input a ip: " ip
read -p "input a netmask: " netmask
for i in {1..4};do
    net=`echo $ip |cut -d. -f$i`
    mask=`echo $netmask |cut -d. -f$i`
    subnetid=$[net&mask]
    if [ $i -eq 1 ];then
        netid=$subnetid
    else
        netid=$netid.$subnetid
    fi
done
echo netid=$netid

其他參考:
[root@centos7 9_2 ]#cat netid1.sh 
#!/bin/bash
read -p "input a ip: " ip
read -p "input a netmask: " netmask
for (( i = 1; i < 5; i++ ));do
    ip1=`echo $ip |cut -d. -f$i`
    netmask1=`echo $netmask |cut -d. -f$i`
    echo -n $[$ip1&$netmask1]       ## 用-n實現不換行追加
    if [ $i -eq 4 ];then            ## 每次輸出一個網絡id字段後並輸出一個點,然後不斷追加
        echo ""
    else
        echo -n "."
    fi
done
[root@centos7 9_2 ]#

7.練習:通過交互式的方式輸入行數和列數,打印出矩形?


[root@centos7 9_2 ]#cat rectangle.sh 
#!/bin/bash
read -p "input line number: " x
read -p "input colume number: " y
for row in `seq $x`;do                                      ## 指定行數打印多行 
    for col in `seq $y`;do                                  ## 通過指定列數打印一行
        echo -e "*\c"
    done
    echo                                                    ## 每一行打印完後換行 
done

優化版:添加顏色顯示,並閃爍
[root@centos7 9_2 ]#cat rectangle.sh 
#!/bin/bash
read -p "input line number: " x
read -p "input colume number: " y
for row in `seq $x`;do                                      ## 指定行數打印多行 
    for col in `seq $y`;do                                  ## 通過指定列數打印一行
        color=$[RANDOM%7+31]                                ## RANDOM%7表示0-6,+31即31-37
        echo -e "\033[1;5;${color}m*\033[0m\c"              ## 1高亮顯示,5閃爍,\c換到行尾表示不換行
    done
    echo                                                    ## 每一行打印完後換行 
done
[root@centos7 9_2 ]#

8.練習:打印等腰三角形

利用for的第二種語法實現
[root@centos7 9_4 ]#cat  fortriangle.sh
#!/bin/bash
read -p "Please input a line number: " line
for ((i=1;i<=line;i++));do
    for ((j=1;j<=$[line-i];j++));do
        echo -n " "
    done
    for ((k=1;k<=$[2*i-1];k++));do
        echo -n "*"
    done
    echo 
done

9.打印九九乘法表

方法1:

[root@centos7 9_4 ]#vim multi.sh
#!/bin/bash
for i in {1..9};do                                  ## 外層循環決定了打幾行,i相當於行號
        for j in `seq $i`;do                        ## j表示其中的一行循環多少遍?
                echo -e "$j*$i=$(($j*$i))\t\c"      ## 計算$j*$i的結果,並以tab分隔,不換行;
        done
        echo                                        ## echo的位置表示打印一行後進行換行;
done

[root@centos7 9_4 ]#sh multi.sh 
1*1=1   
1*2=2   2*2=4   
1*3=3   2*3=6   3*3=9   
1*4=4   2*4=8   3*4=12  4*4=16  
1*5=5   2*5=10  3*5=15  4*5=20  5*5=25  
1*6=6   2*6=12  3*6=18  4*6=24  5*6=30  6*6=36  
1*7=7   2*7=14  3*7=21  4*7=28  5*7=35  6*7=42  7*7=49  
1*8=8   2*8=16  3*8=24  4*8=32  5*8=40  6*8=48  7*8=56  8*8=64  
1*9=9   2*9=18  3*9=27  4*9=36  5*9=45  6*9=54  7*9=63  8*9=72  9*9=81  

思路:找規律,第一個數字是列編號 第二個數字是行號;
先打印一行 ,然後循環打印多行————————打印一行的時候,需要計算循環多少遍?——————最終發現由行號決定循環幾遍

方法2:C語言風格

[root@centos7 9_4 ]#cat for_mult.sh 
#!/bin/bash
for ((i=1;i<=9;i++));do   
    for ((j=1;j<=i;j++));do
        echo -e "$j*$i=$[j*i]\t\c"
    done
    echo 
done

10.在/testdir目錄下創建10個html文件,文件名格式爲數字N(從1到10)加隨機8個字母,如:1AbCdeFgH.html

[root@centos7 9_4 ]#vim create.sh 
#!/bin/bash
for i in {1..10};do
        touch $i`tr -dc "0-9a-zA-Z" < /dev/urandom|head -c8`
done

四、循環之while循環

1.練習:計算1+2+3+..+100的和

[root@centos7 9_4 ]#vim while.sh
#!/bin/bash
sum=0
i=1
while [ $i -le 100 ];do
        let sum+=i
        let i++
done
echo sum=$sum                                                                                                                                                  
"while.sh" [New] 8L, 86C written                           
[root@centos7 9_4 ]#sh while.sh 
sum=5050

2.練習:九九乘法表

 9_4 ]#vim whilemult.sh
#!/bin/bash
i=1
while [ $i -le 9 ];do
        j=1
        while [ $j -le $i ];do
        echo -e "$j*$i=$[$j*$i]\t\c"
        let j++
        done
        echo 
        let i++
done

[root@centos7 9_4 ]#sh whilemult.sh 
1*1=1   
1*2=2   2*2=4   
1*3=3   2*3=6   3*3=9   
1*4=4   2*4=8   3*4=12  4*4=16  
1*5=5   2*5=10  3*5=15  4*5=20  5*5=25  
1*6=6   2*6=12  3*6=18  4*6=24  5*6=30  6*6=36  
1*7=7   2*7=14  3*7=21  4*7=28  5*7=35  6*7=42  7*7=49  
1*8=8   2*8=16  3*8=24  4*8=32  5*8=40  6*8=48  7*8=56  8*8=64  
1*9=9   2*9=18  3*9=27  4*9=36  5*9=45  6*9=54  7*9=63  8*9=72  9*9=

3. 練習:打印等腰三角形

ot@centos7 9_4 ]#cat while_triangle.sh 
#!/bin/bash
read -p "Please input a line number: " line
i=1                                             ## 打印多行
while [ "$i" -le "$line" ];do       
    ## print space                              ## 打印空格
    j=1
    while [ "$j" -le $[line-i] ];do
        echo -n " "             ##或者使用 echo -e " \c"
        let j++
    done 
    ## print *                                  ## 打印*的個數
    k=1
    while [ "$k" -le $[2*i-1] ];do
        echo -n "*"
        let k++
    done
    let i++
    echo    
done

[root@centos7 9_4 ]#sh while_triangle.sh 
Please input a line number: 10
         *
        ***
       *****
      *******
     *********
    ***********
   *************
  ***************
 *****************
*******************

思路:先打出空格——————再打印*的個數
定義總行數:line
當前行:i
當前列:j

中間 所在列=總行數line
當前行從開頭到中間
的個數=i
space=line-i
當前行 的個數=2i-1

4.練習:監控httpd服務的狀態?

#!/bin/bash
SLEEPTIME=10
while : ;do                                             ## :和true都表示爲真
        if killall -0 httpd &> /dev/null ;then          ## kill -0 表示監控進程是否在運行
                true
        else
                service httpd restart
                echo "At `date +'%F %T'` httpd restart" >> /var/log/checkhttpd.log
        fi
        sleep $SLEEPTIME                                ## 等待時間
done

##建議使用nohup script & 放入後臺執行,終端的退出將不影響執行。

5.練習:編寫腳本,利用變量RANDOM生成10個隨機數字,輸出這個10數字,並顯示其中的最大值和最小值

[root@centos7 9_4 ]#cat formaxmin.sh 
#!/bin/bash
echo -e "random list:\c"        
for ((i=0;i<10;i++));do
    rand=$RANDOM
    echo -e " $rand\c"
    if [ $i -eq 0 ];then                    ## 第一次的隨機數字沒有可比的數字,所以既是最大值又是最小值;
        max=$rand
        min=$rand   
    fi
    if [ $max -lt $rand ];then              ## 如果隨機數大於最大值,則rand替換爲最大值;
        max=$rand
    elif [ $min -gt $rand ];then            ## 否則爲假,即隨機數<max,並且<min,則替換爲最小值。
        min=$rand
    else
        true                                ## 如果是其他情況,則默認
    fi
done
echo
echo max is $max
echo min is $min

效果如圖:
[root@centos7 9_4 ]#sh formaxmin.sh 
random list: 18428 5303 6933 16210 2577 4107 23750 16836 3435 14399
max is 23750
min is 2577

五、循環之until循環

注意:爲真,退出
爲假,則執行循環語句

1.練習:查看系統登錄用戶,如果有hacker這個登錄用戶,則踢出去?

[root@centos7 9_4 ]#cat untiltest.sh 
#!/bin/bash
until who|grep -q "^hacker\>";do
    sleep 3
done                                    
## 如果有hacker用戶在登錄,則退出腳本,並執行下面的pkill語句。
pkill -9 -U hacker                      ## 注意 pkill -9 可以殺死用戶所有的進程。

## 優化版:不退出腳本,進入死循環,hacker一旦登錄,則直接踢出去
[root@centos7 9_4 ]#cat untiltest.sh 
#!/bin/bash 
until false; do                         ## 爲假則進入死循環
    who|grep -q "^hacker\>" && pkill -9 -U hacker
    sleep 3
done

其他小練習

1.練習:隨機生成10以內的數字,實現猜字遊戲,提示比較大或小,相等則退出

#!/bin/bash
rand=$[RANDOM%11]                           ## 生成0-10的隨機數字
while read -p "input a number: " num;do
        if [[ ! $num =~ ^[0-9]+$ ]];then    ## 由於直接比較,不是>
數字的話會報錯,所以進行判斷;
                echo "Please input a digit"
                continue                    ## 結束本次循環
        elif [ $num -gt $rand ];then
                echo $num is greater
        elif [ $num -lt $rand ];then
                echo $num is little
        else
                echo "guess OK"
                break                       ## 退出整個循環
        fi
done

2.練習:逐行讀取df的信息,然後判斷分區的利用率是否大於8,大於則進行提示

方法1:

[root@centos7 9_4 ]#cat diskcheck.sh 
#!/bin/bash

df |sed -n "/sd/p"|while read line;do
    name=`echo $line |tr -s " " %|cut -d% -f1`          ## 通過echo $line對讀取到的每一行進行處理
    used=`echo $line |tr -s " " %|cut -d% -f5`
    if [ $used -gt 8 ];then
        echo "$name will be full;$used %"
    fi
done

[root@centos7 9_4 ]#sh diskcheck.sh
/dev/sda2 will be full;9 %
/dev/sda1 will be full;16 %

方法2:

#!/bin/bash
df |while read line;do
    if [[ "$line" =~ /dev/sd.* ]];then
        used=`echo $line|tr -s " " %|cut -d% -f5`

        if [ $used -gt 8 ];then
            echo "$line" |tr -s " " :|cut -d: -f1,5
        fi
    fi
done

[root@centos7 9_4 ]#sh diskcheck1.sh 
/dev/sda2:9%
/dev/sda1:16%

3.練習:掃描/etc/passwd文件每一行,如發現GECOS字段爲空,則填充用戶名和單位電話爲62985600,並提示該用戶的GECOS信息修改成功?

[root@centos7 9_4 ]#cat user.sh 
#!/bin/bash
while read line ;do 
    GECOS=`echo $line|cut -d: -f5`
    USER=`echo $line|cut -d: -f1`
    [ -z "$GECOS" ] && chfn -f $USER -p 2985600 $USER &> /dev/null;
done < /etc/passwd

4.練習: ss -nt查看訪問連接的ip,如果達到兩個,就設置防火牆策略拒絕連接。

[root@centos7 9_4 ]#vim test.sh 
#!/bin/bash
ss -nt|sed -nr '/ESTAB/s/.* (.*):.*/\1/p'|sort|uniq -c|while read line;do     ## 取出ip並統計次數,然後逐行讀取;
IP=`echo $line|cut -d" " -f2`
num=`echo $line|cut -d" " -f1`
        if [ "$num" -ge 2 ];then
                                                iptables -A INPUT -s $IP -j REJECT                            ## 如果連接數>2,則使用防火牆策略阻止連接
        else
                true
        fi
done

5.select菜單

語法:select: select NAME [in WORDS ... ;] do COMMANDS; done

[root@CentOS6 ~ ]#cat  select.sh 
#!/bin/bash
PS3="please choose a digit: "                                   ## PS3專門用來提供輸入
select MENU in jiaozi lamian mifan daoxiaomian quit;do          ## in後面的參數默認按照序號1 2 3 4等一一對應;
    case $MENU in 
    jiaozi)
        echo "Your choose is $REPLY"                            ## 變量REPLY專門用於存儲用戶輸入的結果
        echo "$MENU price is 20"
    ;;
    lamian)
        echo "Your choose is $REPLY"
        echo "$MENU price is 15"
    ;;
    mifan)
        echo "Your choose is $REPLY"
        echo "$MENU price is 18"
    ;;
    daoxiaomian)
        echo "Your choose is $REPLY"
        echo "$MENU price is 12"
    ;;
    quit)
        echo "Your choose is $REPLY"
        break
    ;;
    *)
        echo "Your choose is $REPLY"
        echo "choose again"
    ;;
    esac
done

效果:
[root@CentOS6 ~ ]#sh select.sh 
1) jiaozi
2) lamian
3) mifan
4) daoxiaomian
5) quit
please choose a digit: 1
Your choose is 1
jiaozi price is 20
please choose a digit: 2
Your choose is 2
lamian price is 15
please choose a digit: 5
Your choose is 5
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章