溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Bash Shell腳本編程筆記總結(一)

發(fā)布時間:2020-07-30 07:30:15 來源:網(wǎng)絡 閱讀:1425 作者:332119393 欄目:關系型數(shù)據(jù)庫


本文是上課筆記總結,涉及細節(jié)知識點會在以后文章說明!

bash腳本編程:

腳本程序:解釋器解釋執(zhí)行;


shell: 交互式接口;編程環(huán)境;

shell: 能夠提供一些內(nèi)部命令,并且能通過PATH環(huán)境變量找到外部命令;把命令提交給內(nèi)核啟動為進程;


編程環(huán)境:

流程控制語句:

順序執(zhí)行;

循環(huán)執(zhí)行;

選擇執(zhí)行;


條件測試:真、假

$?

命令的狀態(tài)結果:

0: 真

1-255: 假


過程式的編程語言的元素:變量、流程、函數(shù)、數(shù)組


變量:局部變量、本地變量、環(huán)境變量、位置參數(shù)變量、特殊變量

變量:

數(shù)值型:整型、浮點型、布爾型

字符型:字符串


bash變量是弱類型;默認字符型;


變量引用:${VAR_NAME}

引號:

弱引用:""

強引用:''

命令引用:``


聲明某變量為整型變量:

let VAR_NAME=VALUE
declare -i VAR_NAME=VALUE


聲明某變量為環(huán)境變量:

export VAR_NAME=VALUE
declare -x VAR_NAME=VALUE


腳本的編寫格式:

第一行:寫明解釋器; #!/bin/bash

注釋行:所有以#開頭的行均為注釋行;會被解釋器忽略;


執(zhí)行腳本:

賦予執(zhí)行權限;指明路徑執(zhí)行;

直接傳遞腳本給bash解釋器


bash的選項:

-n: 測試腳本中是否有語法 錯誤;

-x: 調(diào)試執(zhí)行;


算術運算:

$[EXPRESSION]
let VAR_NAME=EXPRESSION
$((EXPRESSION))
$(expr argu1 argu2 argu3)


流程控制之一:for循環(huán)

將一段代碼反復執(zhí)行;

表達式:

for VAR in LIST; do
STATEMENT1
...
done


for VAR in LIST; do statement1; statement2; ...; done


for ((初始化循環(huán)控制變量;循環(huán)條件;修正表達式)); do
循環(huán)體
done


進入條件; 退出條件;

循環(huán)體;STATEMENT1

睡眠:sleep [n]

循環(huán)次數(shù):為列表中的元素的個數(shù);

LIST:列表,包含至少一個元素的字符串集合;

(1) 直接給出;

(2) 數(shù)值列表:

(a) {start..end}

例如:{1..10}

(b) seq [start [step]] end

seq LAST
seq FIRST LAST
seq FIRST STEP LAST

(3) 返回列表的命令;

(4) globbing;

(5) 變量引用;

$*, $@

例如:添加3個用戶,user1, user2, user3; 密碼同用戶名;

#vi useradd.sh
#!/bin/bash
for username in user1 user2 user3; do
useradd $username
echo $username |passwd --stdin $username
done


例如:添加9個用戶,user101...user109;密碼同用戶名;

#vi useradd2.sh
#!/bin/bash
for i in {1..9}; do
useradd user10$i
echo user10$i |passwd --stdin user10$i
done


練習:于/tmp/test目錄中創(chuàng)建10個空文件f1,.., f10;

#vi addfile.sh
#!/bin/bash
directory=/tmp/test-$(date '+%Y%m%h')
mkdir $directory
for i in {1..10} ; do
touch $directory/f$i
done

練習:寫一個腳本,

(1) 創(chuàng)建"/tmp/test-當前時間"目錄;

(2) 添加10用戶tuser1,.., tuser10; 

(3) 在"/tmp/test-當前時間"目錄中,創(chuàng)建10空文件f1,...,f10;

(4) 修改f1的屬主為tuser1;依次類推;

#vi creatdir.sh
#!/bin/bash
dir=/tmp/test-$(date '+%F-%H-%S')
mkdir $dir
for i in {1..10} ; do
        useradd testuser$i
        touch $dir/f$i
        chown testuser$i $dir/f$i
done
rm -rf $dir
userdel testuser$i


練習:求100以內(nèi)所有正整數(shù)之和;

#vi plus.sh
#!/bin/bash
sum=0
for i in `seq 100`;do
sum=$(($sum+$i))
done
echo $sum


練習:求100以內(nèi)所有偶數(shù)之和;以及所有奇數(shù)之和;

#!/bin/bash
declare -i sum=0
for i in `seq 1 2 100`;do
        sum=$(($sum+$i))
done
echo $sum
declare -i sum1=0
for i in `seq 2 2 100`; do
        sum1=$(($sum1+$i))
done
echo $sum1
練習5:計算當前系統(tǒng)上所有用戶ID之和;
#!/bin/bash
sum=0
for i in `cut -d: -f3 /etc/passwd` ; do
        sum=$(($sum+$i))
done
echo $sum


練習:傳遞參數(shù)(文本文件路徑)給腳本,統(tǒng)計所有文件的空白行數(shù)之和;顯示此次共對多少文件進行統(tǒng)計;

#!/bin/bash
sum=0
num=0
echo $#
for i in `seq 1 $# `; do
        num=`grep '^$' $1 |wc -l`
        sum=$(($num+$sum))
        shift
done
echo  $sum


練習:顯示當前系統(tǒng)所有默認shell為bash的用戶的總數(shù);并統(tǒng)計此些用戶ID之和;

for id in `grep "/bin/bash$" /etc/passwd | cut -d: -f3`; do

#!/bin/bash
sum=0
num=0
for i in `grep 'bash$' /etc/passwd |cut -d: -f3` ; do
        sum=$(($sum+$i))
        num=$(($num+1))
done


for的幾種特殊情況:

(1) for省略,會自動獲取腳本參數(shù)列表;

(2) C編程風格:

for ((變量賦值;循環(huán)條件;修正表達式)); do

CMD1

CMD2

done


(3) 循環(huán)嵌套:

for i in [LIST1]; do

CMD1

for j in [LIST2]; do

CMD2

...

done

done


練習:寫一個腳本

(1) ping 172.16.X.Y內(nèi)的所有主機;

172.16.0-255.1-254


for i in {0..255}; do
    for j in {1..254}; do
        ping -c1 -w1 172.16.$i.$j
    done
done


練習:寫個腳本

(1) 傳遞一些目錄給腳本;

(2) 逐個顯示每個目錄下的所有一級文件的內(nèi)容類型;

(3) 統(tǒng)計一個有多少個目錄;一共顯示了多少個文件;


#!/bin/bash
#
declare -i dirs=0
declare -i files=0
for d in $*; do
    for f in $d/*; do
        file $f
        let files++
    done
    let dirs++
done
echo "Directories: $dirs."
echo "Files: $files."



bash命令退出和退出狀態(tài)碼

命令在bash中執(zhí)行結束退出時,其執(zhí)行成功與否可通過退出狀態(tài)碼來記錄

#echo $?


腳本的退出狀態(tài)碼取決于執(zhí)行的最后一條命令;自定義退出狀態(tài)碼:

exit #

成功:0

失?。?-255

#!/bin/bash
ls /varr
retval=$?
echo 'hello'
exit $retvel

以ls /varr的結果狀態(tài)為退出狀態(tài)

注意:提前退出腳本,也可使用exit命令實現(xiàn)


bash 腳本編程之條件測試:

if/then結構


條件測試:

test EXPRESSION
[ EXPRESSION ]
[[ EXPRESSION ]]

COMMAND:使用的是命令退出狀態(tài)碼

1.使用命令執(zhí)行結果

a.使用命令引用

b.使用比較操作符

例如:

                                          

[  `id -u $username ` -lt  500 ]
userid=`id -u $username`
[ $userid  -lt 500]

2.使用命令的退出狀態(tài)碼

a.先運行命令

b.引用狀態(tài)碼

引用方式兩種:

1.if COMMAND &>/dev/null;then

引用的是命令運行的退出狀態(tài)碼

注意:COMMAND不能被使用命令引用,COMMAND的執(zhí)行結果通常沒有意義,所以其結果通常(&>)被定向至/dev/null

2.先執(zhí)行命令,后判斷退出狀態(tài)碼是否為0

COMMAND

retval=$?
if [ $? -eq 0 ] ; then


測試表達式:

(1) 整數(shù)測試;例如:1<2 

(2) 字符串測試;例如:比較字符串相等與否

(3) 文件測試;例如:判斷文件類型


整數(shù)測試:A, B;需要雙目操作符;

A -gt B: 大于

A -ge B: 大于和等于

A -eq B: 等于

A -lt B: 小于

A -le B: 小于等于

A -ne B: 不等于

符合為真,否則為假

注意:命令執(zhí)行結果和狀態(tài)返回結果不一樣,需要判斷。


字符串測試:A, B

A > B

A < B

A >= B

A <= B

A == B或A = B:等值比較

A != B: 不等于

-z A: 判斷A是否為空;空則為真,不空則假;

-n A:判斷A是否不空;不空則為值,空則為假;

[ $A = $B ]

"$A" =~ PATTERN

如果變量A中給定的字符串能被模式匹配即為真,否則為假

例如:過濾fdisk -l 結果的字符串

#disk=/dev/sda
#[[ $dsk=~/dev/sd[a-z] ]]     變量和模式匹配
#echo $?
0 為真
#disk=/dev/xda
#[[ $disk =~ /dev/sd[a-z] ]]       變量和模式不匹配
#echo $?
1  為假


文件測試:$file

-e $file: 是否存在;存在則為真;

-a $file: 同上;棄用;

-f $file: 文件是否存在,且為普通文件;

-d $file: 是否存在且為目錄;

-h $file: 是否存在且為符號鏈接文件;

-L $file:同上

-b $file: 是否存在且為塊設備文件;

-c $file: 是否存在且為字符設備文件;

-S $file: 是否存在且為套接字文件:

-p $file: 是否存在且為管道文件;


-r $file: 當前用戶對此文件是否擁有讀權限;

-w $file:                         寫

-x $file:                         執(zhí)行權限;


-u $file: 文件是否擁有suid權限;

-g $file:文件是否擁有sgid權限;

-k $file: 文件是否擁有sticky權限;


-O $file: 當前用戶是否為文件的屬主;

-G $file: 當前用戶是否屬于文件的屬組;


-N $file: 文件自從上一次被讀取之后,是否被修改過;


$f1 -nt $f2: 文件f1是否比文件f2新;

$f1 -ot $f2: 文件f1是否比文件f2舊;

$f1 -ef $f2: f1和f2是否為同一個文件的硬鏈接;


練習:寫一個腳本,傳遞一個文件路徑參數(shù)給腳本

(1) 存在,則顯示有此文件;

(2) 否則,則顯示無此文件

#!/bin/bash
if [ -e $1 ] ; then
echo "$1 exist"
else
echo "$1 is not exist"
fi


練習:寫一個腳本,傳遞一個文件路徑參數(shù)給腳本

(1) 如果腳本無參數(shù),則顯示必須給至少一個參數(shù),退出腳本;退出碼5;

(2) 路徑指向的文件如果不存在,則直接退出腳本;退出碼為6;

(3) 判斷文件類型:

(a) 如果是普通文件,則顯示為"common file";

(b) 如果是目錄,則顯示為"directory";

(c) 如果是符號鏈接,則顯示為"symbolic link file";

(d) 如果是塊設備,則顯示為“block device file";

(e) 如果是字符設備,則顯示為"character device file";

(f) 否則,則顯示為“unkown”;

#!/bin/bash
if [ $# -lt 1 ] ; then
        echo "you mast input a number"
        exit 5 
if [ ! -e $1 ] ; then
        echo "the file is not exist"
        exit 6
if [ -f $1 ] ; then
        echo "$1 is commonfile"
elif [ -d $1 ] ; then
        echo "$1 is directory"
elif [ -L $1 ] ; then
        echo "$1 is symbolic link file"
elif [ -b $1 ] ; then
        echo "$1 is block device file"
elif [ -c $1 ] ; then
        echo "$1 is character device file"
else
        echo "$1 is unknow"
fi


練習:寫一個腳本,其使用格式如下所示(其中所有的script.sh均為用戶給定的腳本名稱,其要跟隨腳本名稱變化):

script.sh {start|stop|restart|status}

(1) 調(diào)用時至少傳遞一個參數(shù);否則,則顯示幫助信息,并退出腳本;

(2) 如果參數(shù)為“start”, 則創(chuàng)建空文件/var/lock/subsys/script.sh,并顯示“starting script.sh successfully.”;

(3) 如果參數(shù)為“stop”,則刪除空文件/var/lock/subsys/script.sh,并顯示“stopping script.sh successfully.”;

(4) 如果參數(shù)為“restart”,則刪除空文件/var/lock/subsys/script.sh,并顯示“stopping script.sh successfully.”;而后重新創(chuàng)建之,并顯示“restarting script.sh successfully.”;

(5) 如果參數(shù)為“status”,則

(a) 如果文件/var/lock/subsys/script.sh文件存在,則顯示“running”;

(b) 否則,則顯示為"stopped"

(6) 其它任意參數(shù),均顯示幫助信息后退出;幫助信息格式為命令使用格式;

 

#!/bin/bash
#
# chkconfig: 2345 95 5
# description: test service script
#
prog=`basename $0`
lockfile=/var/lock/subsys/$prog
if [ $# -lt 1 ]; then
    echo "Usage: $prog {start|stop|restart|status}"
    exit 1
fi
if [ "$1" == 'start' ]; then
    if [ -e $lockfile ]; then
echo "$prog is aleady running."
exit 1
    else
touch $lockfile
echo "Starting $prog succefully."
    fi
elif [ "$1" == 'stop' ]; then
    if [ -e $lockfile ]; then
rm -f $lockfile
echo "Stopping $prog succefully."
    else
echo "$prog is not running."
exit 1
    fi
elif [ "$1" == 'restart' ]; then
    if [ -e $lockfile ]; then
rm -f $lockfile
echo "Stopping $prog succefully."
touch $lockfile
echo "Starting $prog succefully."
    else
touch $lockfile
echo "Starting $prog succefully."
    fi
elif [ "$1" == 'status' ];then
    if [ -e $lockfile ];then
echo "$prog is running."
    else
echo "$prog is stopped."
    fi
else
    echo "Usage: $prog {start|restart|status|stop}"
    exit 1
fi

條件測試語法:

單分支:

if CONDITION; then
CMD1
CMD2
...
fi


例如:求100以內(nèi)所有偶數(shù)之和;遍歷100以內(nèi)所有正整數(shù);

#!/bin/bash
declare i sum=0
for i in {1..100} ; do
        if [[ $[$i%2] -eq 0 ]] ; then
                sum=$(($sum+$i))
        fi
done
echo $sum


例如:傳遞一個參數(shù)給腳本,而后以此參數(shù)為用戶名,添加此用戶;

#!/bin/bash           

if [ $# -ge 1 ];then

useradd $1

fi


if可以嵌套:

if CONDITION1; then
if CONDITION2; then
CMD
fi
fi


例如:傳遞一個參數(shù)給腳本,而后以此參數(shù)為用戶名,不存在時,則添加此用戶;

條件取反:

! CONDITION

#!/bin/bash            至少有個參數(shù)
if [ $# -ge 1 ];then
if ! id $1 &>/dev/null;then           條件取反
useradd $1
fi
fi

if條件判斷為真才能執(zhí)行then下面的步驟

id $1 的狀態(tài)如果是0,表示執(zhí)行狀態(tài)成功了,取反后條件是假,then就不執(zhí)行

id $1 的執(zhí)行狀態(tài)如果是1,表示執(zhí)行狀態(tài)是失敗的,取反后條件判斷是真,then就開始執(zhí)行


練習:寫一個腳本

(1) 添加用戶testuser1-tuser10;

(2) 用戶不存在時才添加;

(3) 統(tǒng)計真正添加的用戶數(shù);

#!/bin/bash
#
declare -i newusers=0
for i in {1..10}; do
    if ! id testuser$i &> /dev/null; then
        useradd testuser$i
        let newusers++
    fi
done
echo "New users: $newusers."


練習: 寫一個腳本

(1) 用ping命令測試172.16.100.X內(nèi)的所有主機;

(2) 將在線的主機輸出出來;

#!/bin/bash
#
for i in {1..254}; do
    if ping -c1 -w1 172.16.100.$i &> /dev/null; then
        echo "172.16.100.$i is up."
    fi
done


雙分支結構:

if CONDITION-TRUE; then
分支1
else
分支2
fi


練習1: 寫一個腳本

(1) 用ping命令測試172.16.100.X內(nèi)的所有主機;

(2) 將所有主機的在線狀態(tài)輸出出來;

#!/bin/bash
for i in {1..254}do
if ping -c1 -w1 172.16.100.$i &>/dev/null;then
echo "172.16.100.$i is up"
else
echo "172.16.100.$i is down"
fi
done


練習:寫一個腳本

(1) 傳遞兩個整數(shù)參數(shù)給腳本;

(2) 返回其較大一個;

#!/bin/bash
declare -i max=0
for i in $* ; do
if [ $i -gt $max ] ; then
max=$i
fi
done
echo $max


練習:寫一個腳本

(1) 傳遞兩個以上的整數(shù)給腳本;

(2) 返回其較大者;

#!/bin/bash
#
declare -i max=0
for i in $*; do
    if [ $i -gt $max ]; then
        max=$i
    fi
done
echo "max: $max."


練習: 寫一個腳本

(1) 取得當前的主機名;

(2) 如果當前的主機名為localhost,則將其修改為oracle;否則,顯示其名稱;

#!/bin/bash
hostname=`hostname`
if [ "$hostname" == 'localhost' ]; then
        hostname oracle
        echo "oracle" > /proc/sys/kernel/hostname
fi

練習:寫一個腳本

(1) 傳遞兩個文本文件路徑給腳本;

(2) 顯示兩個文件中空白行數(shù)較多的文件及其空白行數(shù);

(3) 顯示兩個文件中總行數(shù)較多的文件及其行數(shù);

#!/bin/bash
if [ $# -ge 2 ] ; then
        if [[ $(wc -l $1|cut -d" " -f1 ) -gt $(wc -l $2| cut -d" " -f1 ) ]] ; then
                if [[ $(grep "^$" $1 | wc -l) -gt $(grep "^$" $2 | wc -l) ]] ; then
                        echo "the more space line file is $1 "
                        echo "the file space line is $(grep "^$" $1 | wc -l)"
                else
                        echo "the more space line file is $2 "
                        echo "the file space line is $(grep "^$" $2 | wc -l)"
                fi
                echo "the more line file is $1 "
                echo "the line have $(wc -l $1)"
        else
                echo "the more line file is $2 "
                echo "the line have $(wc -l $2)"
        fi
fi


練習:寫一個腳本

(1) 傳遞一個參數(shù)給腳本,此參數(shù)為用戶名;

(2) 如果用戶存在,則執(zhí)行如下任務

(a) 如果用戶的id號小于500,顯示其為管理員或系統(tǒng)用戶;

(b) 否則,顯示其為普通用戶;

(3) 如果用戶不存在,則添加之;

#!/bin/bash
#
if id $1 &> /dev/null; then
     userid=`id -u $1`
    if [ $userid -lt 500 ]; then
        echo "$1 is sysadmin or sysuser."
    else
        echo "A common user."
    fi
else
    useradd $1
    if [ $? -eq 0 ];then
        echo "Add user $1."
    else
        echo "Cannot add $1."
    fi
fi



多分支的if語句:

if CONDITION1-TRUE; then
分支1
elif CONDITION2-TRUE; then
分支2
elif CONDITION3-TRUE; then
分支3
...
else
分支n
fi


練習:傳遞一個參數(shù)給腳本

如果參數(shù)為quit,則顯示說要退出腳本;

如果參數(shù)為yes,則顯示說繼續(xù);

否則,則顯示為無法識別;

#!/bin/bash
if [[ "$1" == 'quit' ]] ; then
echo "quit"
elif [[ "$1" == 'yes' ]] ; then
echo "yes"
else 
echo "unkown"
fi


練習:傳遞一個用戶名參數(shù)給腳本

(1) 如果用戶的id號為0,則顯示為管理員;

(2) 如果用戶的id號大于6000,則顯示為guest; 

(3) 如果用戶的id號大于500,則顯示為普通用戶;

(4) 如果用戶的id號大于0, 則顯示為系統(tǒng)用戶;

(5) 否則,無法識別;

#!/bin/bash
if id $1 &/dev/null ; then
userid=`id -u $1`
if [ $userid -eq 0 ] ; then
echo "$1 is sysadmin"
elif [ $userid -gt 60000 ] ; then
echo "$1 is a guest user"
elif [ $userid -gt 500 ] ; then
echo "$1 is a common user"
elif [ $userid -gt 0 ] ; then
echo "$1 is a system user"
else
echo "$1 is unknown "
fi



練習3:寫一個腳本;

(1) 傳遞一個磁盤設備文件給腳本;

(2) 判斷此設備是否存在;如果存在,則清除此設備上的所有分區(qū);

(3) 否則,則無此設備;

#!/bin/bash
if fdisk -l $1  ; then
dd if=/dev/zero of=$1 bs=512 count=1
else
echo "no such device"
fi





組合測試條件1:

給條件添加邏輯操作符;

或, -o: [ -z "$hostname" -o "$hostname" == 'localhost' ]

與, -a: [ $uid -gt 0 -a $uid -lt 500 ]

非:[ ! EXPRESSION ]


練習:寫一個腳本,取得當前的主機名,判斷

(1) 如果主機名為空或為"localhost",則將其命名為stuX.oracle.com;

(2) 否則,則顯示主機名即可;

#!/bin/bash
#
hostname=`hostname`
if [ "$hostname" == 'localhost' -o -z "$hostname" ]; then
    hostname stu100.oracle.com
    #echo "stu100.oracle.com" > /proc/sys/kernel/hostname
else
    echo "The hostname is: $hostname."
fi


練習:寫一個腳本,傳遞一個參數(shù)給腳本;此參數(shù)為用戶名

(1) 如果用戶不存在,則直接退出腳本;

(2) 如果用戶存在,

id=0,則顯示為“system admin”

0<id<500,則顯示為“system user”

id>=500,則顯示為“Common user.”

#!/bin/bash
#
if ! id $1 &> /dev/null; then
    echo "No such user."
    exit 1
fi
uid=$(id -u $1)
if [ $uid -eq 0 ]; then
    echo "Sys Admin."
elif [ $uid -gt 0 -a $uid -lt 500 ];then
    echo "Sys User."
else
    echo "Common User."
fi


練習:寫一個腳本,傳遞一個參數(shù)給腳本;此參數(shù)為用戶名

(1) 如果用戶不存在,則直接退出腳本;

(2) 如果用戶的id號大于等于500,且其shell為“以sh結尾的”類型,則顯示“a user can log system.”;否則,顯示用戶無法登錄;

#!/bin/bash
#
if ! id $1 &> /dev/null; then
    echo "No such user."
    exit 1
fi
if [[ `id -u $1` -ge 500 ]] && [[ `grep "^$1\>" /etc/passwd | cut -d: -f7` =~ /bin/.*sh$ ]]; then
    echo "a user can log system."
else
    echo "a user cannot log."
fi


組合測試條件2:

短路操作符

與:COMMAND1 && COMMAND2

COMMAND1的退出狀態(tài)如果為假,則COMMAND2不用運行,即可有最終結果;

或:COMMAND1 || COMMAND2

COMMAND1的退出狀態(tài)如果為真,則COMMAND2不用運行,即可有最終結果;

非:! COMMAND


[ ! -d /tmp/test ] && mkdir /tmp/test^C
[ -d /tmp/test ] || mkdir /tmp/test


練習:寫一個腳本,完成如下任務:

(1) 如果httpd進程或nginx進程處于運行中,則顯示“web server started.”,并顯示其監(jiān)聽的端口;

(2) 否則顯示“no web server.”;

if pidof httpd &> /dev/null && pidof nginx &> /dev/null;

 


交互式腳本:

read [OPTIONS] [name ...]

-p "PROMPT"

-t #: 超時時長


給變量以默認值:

[ -z "$VAR" ] && VAR=VALUE


練習:顯示如下菜單給用戶

cpu) show cpu infomation;

mem) show memory infomation;

disk) show disk infomation;

*) quit

提示用戶鍵入選項:

(1) cpu: 顯示CPU相關的信息

(2) mem: 顯示內(nèi)存相關的信息

(3) disk: 列出磁盤設備

(4) 其它任何信息,即為退出腳本


#!/bin/bash
#
cat << EOF
cpu) show cpu infomation;
mem) show memory infomation;
disk) show disk infomation;
*) quit
=========================================================
EOF
read -p "Your  choice: " choice
if [[ "$choice" == 'cpu' ]]; then
    lscpu
elif [[ "$choice" == 'mem' ]]; then
    free -m
elif [[ "$choice" == 'disk' ]]; then
    fdisk -l /dev/sd[a-z]
else
    echo "quit"
    exit 0
fi

case語句:

簡潔版的多分支if語句;


語法格式:

case 變量引用  in 
PATTERN1)
分支1
;;
PATTERN2)
分支2
;;
...
*)
分支n
;;
esac


PATTERN可使用通配符:

*:任意長度的任意字符

?: 任意單個字符

[]:指定范圍內(nèi)的任意單個字符

a|b: a或者b


練習:寫一個腳本,使用tar工具把/etc目錄備份至/backup目錄中,名字為/backup/etc-日期時間.tar.{xz|bz2|gz};

(1) 顯示如下菜單

xz) xz compress tool

gzip) gzip compress tool

bzip2) bzip2 compress tool

*) wrong choice and quit

(2) 根據(jù)用戶選擇的工具,執(zhí)行相應操作;如果用戶沒有鍵入任何數(shù)據(jù),則默認使用xz;


#!/bin/bash
cat<<EOF
        xz)xz compress tool
        gzip)gzip compress tool
        bzip2)bzip2 compress tool
        *)wrong choice and quit
=======================================================
EOF
read -t 5 -p "pls input the choice:" command
[ -z $command ] && command="xz"
 ! [  -d /backup ] ||  mkdir /backup
file_path=/backup/etc"-$(date +%Y%m%d%H%M).tar"
echo $file_path
case $command in
        "xz")
                echo "xz"
                #tar -Jcf  $file_path.xz /etc/* 
                ;;
        "gzip")
                echo "gzip"
                #tar -zcf  $file_path.gz /etc/*
                ;;
        "bzip2")
                echo "bzip2"
                #tar -jcf  $file_path.bzip2 /etc/*
                ;;
        *)
                echo "wrong choice"
                ;;
esac

練習:使用case語句編寫一個服務腳本框架

#!/bin/bash
#
# chkconfig:
# description: 
#
prog=`basename $0`
lockfile=/var/lock/subsys/$prog
case $1 in 
"start")
if [ -e $lockfile ];then
echo "$prog is aleady running"
exit 1
else
touch $lockfile
echo "Starting $prog succefully"
fi
;;
"stop")
if [ -e $lockfile ];then
rm -f $lockfile
echo "Stopping $prog succefully"
else
echo "$porg is not running"
exit 1
fi
;;
"restart")
if [ -e $lockfile ];then
rm -f $lockfile
echo "Stopping $prog succefully"
touch $lockfile
echo "Starting $prog succefully"
else
touch $lockfile
echo "Starting $prog succefully"
        fi
;;
"status")
if [ -e $lockfile ];then
echo "$prog is running"
else
echo "$prog is stopped"
fi
;;
*)
echo "Usage: $prog {start|restart|status|stop}"
exit 1
;;
esac




bash中生成偽隨機數(shù):$RANDOM

0-32767


練習:生成10個隨機數(shù),返回其最大值;


#!/bin/bash
declare -i max=0
for i in {1..10};do
random=$RANDOM
LIST="$LIST $random"
if [ $random -ge $max ];then
max=$random
fi
done
echo "List Number:$LIST"
echo "Max Number:$max"



練習:從所有同學中隨機挑選一個學號;

#!/bin/bash
i=$[$RANDOM%36+1]
j=$[$RANDOM%36+1]
while [ $i -ne $j ] ; do
        echo $i
        echo $j
        break
done
# echo $[`date +%N`%36+1]
# echo $[`head /dev/urandom | cksum |cut -d" " -f1`%36+1]




while、until循環(huán)和函數(shù):


練習:使用for循環(huán),打印九九乘法表

#!/bin/bash
#
for i in {1..9}; do
    for j in `seq 1 $i`; do
        echo -n -e "${j}x${i}=$[$i*$j]\t"
    done
    echo
done


while循環(huán):

while CONDITION; do

循環(huán)體

循環(huán)控制變量的修正表達式

done


當CONDITION為“真”進入循環(huán),直到“假”退出循環(huán);


練習:計算100以內(nèi)所有偶數(shù)之和;

#!/bin/bash
#
declare -i i=1
declare -i evensum=0
while [ $i -le 100 ]; do
   if [ $[$i%2] -eq 0 ]; then
let evensum+=$i
   fi
   let i++
done
echo $evensum


until循環(huán):

until CONDITION; do

循環(huán)體

循環(huán)控制變量修正表達式

done


當CONDITION為“假”時進入循環(huán);為“真”退出循環(huán);


練習:計算100以內(nèi)所有偶數(shù)之和;

#!/bin/bash
#
declare i=1
declare evensum=0
until [ $i -gt 100 ]; do
    if [ $[$i%2] -eq 0 ]; then
let evensum+=$i
    fi
    let i++
done
echo $evensum


練習:分別使用while和until循環(huán)實現(xiàn)添加10個用戶:myuser1-myuser10

#!/bin/bash
#
declare -i i=1
declare -i j=0
until [ $i -gt 10 ]; do
    if ! id myuser$i &> /dev/null; then
useradd myuser$i
    let j++
    fi
    let i++
done
echo "Add users [total]: $j."


練習:打印九九乘法表,要求內(nèi)外層循環(huán)分別使用while或until;

#!/bin/bash
declare i=1
declare j=1
while [ $i -le 9 ] ; do
while [ $j -le 9 ] ; do
if [ $j -gt $i ] ; then
break
fi
echo -e -n "${j}x${i}=$[$i*$j]\t"
let j++
done
echo
let j=1
let i++
done



循環(huán)控制命令:

break:提前退出循環(huán);

break [N]: 退出N層循環(huán);N省略時表示退出break語句所在的循環(huán);

continue: 提前結束本輪循環(huán),而直接進入下輪循環(huán);

continue [N]:提前第N層的循環(huán)的本輪循環(huán),而直接進入下輪循環(huán);


while CONDITION; do

CMD1

if CONDITION2; then

break [N]

fi

CMD2

...

done


死循環(huán):

while true; do

循環(huán)體

done


until false; do

循環(huán)體

done


練習:寫一個腳本,判斷給定的用戶是否登錄了當前系統(tǒng);

(1) 如果登錄了,則腳本終止;

(2) 每5秒種,查看一次用戶是否登錄;


方法一:使用until循環(huán)

#!/bin/bash
#
declare -i status=0
who | grep "centos" &> /dev/null
status=$?
until [ $status -eq 0 ]; do
    sleep 5
    who | grep "centos" &> /dev/null
    status=$?
done
echo "centos is logged on."



方法二:簡化版

#!/bin/bash
#
declare -i status=0
until who | grep "centos" &> /dev/null; do
    sleep 5
done
echo "centos is logged on."


方法三:使用死循環(huán)

#!/bin/bash
#
while true; do
    who | grep "centos" &> /dev/null
    if [ $? -eq 0 ];then
break
    fi
    sleep 5
done
echo "centos is logged."


while的特殊用法:遍歷指定文件的每一行

while read line; do

循環(huán)體

done < /path/from/somefile


練習:找出其UID為偶數(shù)的所有用戶的用戶名;并顯示其ID號;


#!/bin/bash
#
file=/etc/passwd
while read line; do
    userid=`echo $line | cut -d: -f3`
    if [ $[$userid%2] -eq 0 ]; then
echo $line | cut -d: -f1,3
    fi
done < $file


練習:輸出給定的文件的偶數(shù)行的行號,以及其行內(nèi)信息統(tǒng)統(tǒng)改為大寫字母輸出;

#!/bin/bash
declare -i i=1
while read line; do
    if [ $[$i%2] -eq 0 ]; then
    echo -n "$i "
    echo $line | tr 'a-z' 'A-Z'
    fi
    let i++
done < /path/from/somefile


練習:顯示如下菜單給用戶

cpu) cpuifno

mem) memory infomation

disk) disk infomation

quit) quit


(1) 用戶給定的選項后,顯示相應的信息;而后提示用戶再次選擇;

(2) 非正確選擇也提示用戶重新選擇,并說明,如果想退出請輸入"quit";


#!/bin/bash
#
while true; do
cat << EOF
cpu) cpu
mem) memory
disk) disk
quit) quit
EOF
    read -p "Your choice: " choice
    case $choice in
    cpu)
        lscpu ;;
    mem)
        free ;;
    disk)
        fdisk -l /dev/sd[a-z] ;;
    quit)
        break ;;
    esac
done



函數(shù):function

過程式編程:代碼重用

模塊化編程;

簡潔


語法:

function f_name {

函數(shù)體

}


f_name() {

函數(shù)體

}


調(diào)用:使用函數(shù)名

函數(shù)名出現(xiàn)的地方,會被自動替換為函數(shù)代碼;


練習:利用函數(shù)改寫此前的服務腳本:

#!/bin/bash
#
prog=`basename $0`
lockfile=/var/lock/subsys/$prog
start() {
    if [ -e $lockfile ]; then
        echo "$prog is already running."
    else
        touch $lockfile
        [ $? -eq 0 ] && echo "Starting $prog finished."
    fi
}
stop() {
    if [ -e $lockfile ]; then
        rm -f $lockfile
        [ $? -eq 0 ] && echo "Stoping $prog finished."
    else
        echo "$prog is stopped yet."
    fi
}
case $1 in
"start")
    start ;;
"stop")
    stop ;;
"restart")
    stop
    start ;;
*)
    echo "Usage: $prog {start|stop|restart}"
    exit 1
esac

函數(shù)的返回值

函數(shù)的執(zhí)行結果返回值:

函數(shù)中使用打印語句:echo, printf

函數(shù)體中OS命令執(zhí)行結果的輸出

函數(shù)的退出狀態(tài)碼

默認取決于函數(shù)體執(zhí)行的最后一個命令的退出狀態(tài)碼;

自定義退出狀態(tài)碼:

return [0-255]

注意:函數(shù)體運行時,一旦遇到return語句,函數(shù)即返回;


函數(shù)可接受參數(shù)

傳遞參數(shù)給函數(shù):調(diào)用函數(shù)時,在函數(shù)名后給出參數(shù)列表即可;例如“testfunc arg1 arg2 arg3”


在函數(shù)體中可使用$1, $2,...來調(diào)用傳遞過來的各參數(shù);

可使用類似腳本的特殊變量:

$*, $@: 一次性獲取參數(shù)列表:

$#: 參數(shù)的個數(shù)


判定用戶輸入用戶名是否正確與否分別執(zhí)行不同操作

#!/bin/bash
#
showuserinfo() {
    [ $# -lt 1 ] && return 1
    ! id $1 &> /dev/null && return 2
    grep "^$1\>" /etc/passwd | cut -d: -f7
    [ $? -eq 0 ] && return 0 || return 3
}
while true; do
    read -p "Enter a username: " username
    [ "$username" == 'quit' ] && break
    showuserinfo $username
    [ $? -ne 0 ] && echo "There is something wrong."
done



練習:利用函數(shù)實現(xiàn)打印九九乘法表;

#!/bin/bash
func() {
declare i=1
declare j=1
while [ $i -le 9 ] ; do
        while [ $j -le 9 ] ; do
                if [ $j -gt $i ] ; then
                        break
                fi
                echo -e -n "{$j}x$i=$[$i*$j]\t"
                let j++
        done
                echo
                let j=1
                let i++
        done
}
func



練習:寫一個腳本,完成如下功能(使用函數(shù)):

         1、提示用戶輸入一個可執(zhí)行命令;

         2、獲取這個命令所依賴的所有庫文件(使用ldd命令);

         3、復制命令至/mnt/sysroot/對應的目錄中

    解釋:假設,如果復制的是cat命令,其可執(zhí)行程序的路徑是/bin/cat,那么就要將/bin/cat復制到/mnt/sysroot/bin/目錄中,如果復制的是useradd命令,而useradd的可執(zhí)行文件路徑為/usr/sbin/useradd,那么就要將其復制到/mnt/sysroot/usr/sbin/目錄中;

         4、復制各庫文件至/mnt/sysroot/對應的目錄中;

#!/bin/bash
#
target=/mnt/sysroot
[ -d $target ] || mkdir $target
preCmd() {
    if which $1 &> /dev/null; then
cmdpath=$(which --skip-alias $1)
return 0
    else
echo "No such command."
return 1
    fi
}
cmdCopy() {
    cmddir=$(dirname $cmdpath)
    [ -d $target/$cmddir ] || mkdir -p $target/$cmddir
    [ -f $target/$cmdpath ] || cp $1 $target/$cmddir
    return 0
}
libCopy() {
    for lib in $(ldd $1 | grep -E -o "/[^[:space:]]+"); do
libdir=$(dirname $lib)
[ -d $target/$libdir ] || mkdir -p $target/$libdir
[ -f $target/$lib ] || cp $lib $target/$libdir
    done
    return 0
}
main() {
    while true; do
        read -p "Plz enter a command(quit for quiting): " cmd
        [ "$cmd" == 'quit' ] && break
        preCmd $cmd
        if [ $? -eq 0 ]; then
   cmdCopy $cmdpath
            libCopy $cmdpath
        fi
    done
}
main



變量的作用域

本地變量:整個腳本,在腳本的函數(shù)中也可調(diào)用,也可修改;

局部變量:函數(shù)調(diào)用的整個生命周期;

local VAR=VALUE


函數(shù)遞歸

函數(shù)直接或間接調(diào)用函數(shù)自身;

1 1 2 3 5 8 13

階乘:10!

n(n-1)!

n(n-1)(n-2)!

階乘函數(shù)

fact() {

if [ $1 -eq 0 -o $1 -eq 1 ]; then

echo 1

else

  echo $[$1*$(fact $[$1-1])]

fi

}

下一篇接:Bash Shell腳本編程筆記總結(二)

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI