bash腳本編程:
過程式編程語言
順序執(zhí)行
選擇執(zhí)行
循環(huán)執(zhí)行
循環(huán)執(zhí)行:必須有進(jìn)入條件和退出條件
-
函數(shù):結(jié)構(gòu)化編程及代碼重用
function
選擇執(zhí)行:
if 判斷條件匪凉;then
條件為真的分支代碼
fi
if 判斷條件;then
添加為真的分支代碼
else
條件為假的分支代碼
fi
eg:
新建用戶
#!/bin/bash
## 如果腳本參數(shù)小于1蹬叭,則退出
if [ $# -lt 1 ];then
echo "At least one argument"
exit 1
fi
## 判斷$1用戶是否存在藕咏,用戶不存在則創(chuàng)建
if id $1 &> /dev/null;then
echo "$1 exists"
exit 0
else
useradd $1
[ $? -eq 0 ] && echo "$1" | passwd --stdin $1 &> /dev/null || exit 1
fi
多分支
if 判斷條件 1 ; then
條件為真的分支代碼
elif 判斷條件 2 ; then
條件為真的分支代碼
elif 判斷條件 3 ; then
條件為真的分支代碼
else
以上條件都為假的分支代碼
fi
- 逐條件進(jìn)行判斷,第一次遇為“真”條件時(shí)秽五,執(zhí)行其分支孽查,而后結(jié)束整個(gè)if
循環(huán)
- 循環(huán)執(zhí)行
將某代碼段重復(fù)運(yùn)行多次
重復(fù)運(yùn)行多少次:
循環(huán)次數(shù)事先已知
循環(huán)次數(shù)事先未知
有進(jìn)入條件和退出條件
- for, while, until
for循環(huán)語法:
for NAME in LIST;do
循環(huán)體
done
執(zhí)行機(jī)制
依次將列表中的元素賦值給“變量名”; 每次賦值后即執(zhí)行一次循環(huán)體;直到列表中的元素耗盡,循環(huán)結(jié)束循環(huán)列表生成方式:
(1)直接給出列表
(2)整數(shù)列表
{start..end}
$(seq [start [step]]end)
(3)glob(統(tǒng)配路徑下的所有文件)如:*.sh
/etc/rc.d/rc3.d/k*
(4)返回列表的命令
$(COMMAND)
(5)變量引用:
$@,$*
eg:
通過ping命令探測172.17.250.1-254范圍內(nèi)的所有主機(jī)的在線狀態(tài)
#!/bin/bash
net='172.17.253'
uphost=0
downhost=0
for i in {1..20};do
ping -c 1 -v 1 ${net}.$i &> /dev/null
if [ $? -eq 0 ];then
echo "${net}.$i is up"
let uphost++
else
echo "${net}.$i is down"
let downhost++
fi
done
echo "Up host:$uphost"
echo "Down host:$downhost"
while循環(huán):
while CONDITON;do
循環(huán)體
done
CONDITION:循環(huán)控制列表:進(jìn)入循環(huán)之前坦喘,先做一次判斷盲再;每一次循環(huán)之后會再次做判斷
條件為“true”,則執(zhí)行一次循環(huán):直到條件測試狀態(tài)為“false”終止循環(huán)瓣铣;
因此:CONDITION一般應(yīng)該有循環(huán)控制變量答朋,而此變量的值會在循環(huán)體不斷的被修正
進(jìn)入條件:CONDITION 為true
退出條件:CONDITION 為false
示例
1 . 求100以內(nèi)所有正整數(shù)之和
declare -i sum=0
declare -i i=1
while [ $i -le 100 ];do
let sum+=$i
let i++
done
echo "i=$i"
echo "Summary:$sum"
2 . 添加10個(gè)用戶
declare -i i=1
declare -i users=0
while [ $i -le 1 ];do
if ! id user$i &> /dev/null;then
useradd user$i
echo "Add user:user$i"
let users++
fi
let i++
done
echo "Add $users users"
3 . 通過ping命令探測172.17.253.1-254范圍的所有主機(jī)的在線狀態(tài):(用while循環(huán))
declare -i i=1
declare -i uphosts=0
declare -i downhosts=0
net='172.17.253'
while [ $i -le 20 ];do
if ping -c 1 -w 1 $net.$i &> /dev/null;then
echo "$net.$i is up"
let uphosts++
else
echo "$net.$i is downhosts"
let downhosts++
fi
let i++
done
echo "Up hosts:$uphosts"
echo "Down host:$downhosts"
4 . 打印九九乘法表:(分別使用for和while循環(huán)實(shí)現(xiàn))
for語句
for j in {1..9};do
for i in $(seq 1 $j);do
echo -n -e "${i}X${j}=$[$i*$j]\t"
done
echo
done
while語句
declare -i i=1
declare -i j=1
while [ $j -le 9 ];do
while [ $i -le $j ];do
echo -e -n "${i}X${j}=$[$i*$j]\t"
let i++
done
echo
let i=1
let j++
done
5 . 利用RANDOM生成10個(gè)隨機(jī)數(shù)字,輸出這10個(gè)數(shù)字棠笑,并顯示其中的最大值和最小值
#!/bin/bash
declare -i max=0
declare -i min=0
declare -i i=1
#max=$rand
#min=$rand
while [ $i -le 9 ];do
rand=$RANDOM
echo $rand
if [ $i -eq 1 ];then
max=$rand
min=$rand
fi
if [ $rand -gt $max ];then
max=$rand
fi
if [ $rand -lt $min ];then
min=$rand
fi
let i++
done
echo "MAX:$max"
echo "MIN:$min"
unil
unil COMDITION;do
循環(huán)體
done
循環(huán)條件為:false
退出條件為:true
示例
1 . 求100以內(nèi)所有正整數(shù)之和
/bin/bash
#!
declare -i i=1
declare -i sum=0
until [ $i -gt 100 ];do
let sum+=$i
let i++
done
echo "Sum:$sum"
2 . 打印九九乘法表
#!/bin/bash
# filename timetale3.sh
# author:danran
# time is 2017-06-22
declare -i j=1
declare -i i=1
until [ $j -gt 9 ];do
until [ $i -gt $j ];do
echo -n -e "${i}X${j}=$[$i*$j]\t"
let i++
done
echo
let i=1
let j++
done
循環(huán)控制語句(用于循環(huán)體中)
continue [N]:提前結(jié)束第N層的本輪循環(huán)梦碗,而直接進(jìn)入下一輪判斷
while CONDTITION1;do
CMD1
...
if CONDITION;then
continue
fi
CMDn
...
done
break [N]:提前結(jié)束循環(huán)
break [N] :提前結(jié)束第N 層循環(huán),
while CONDTITION1;do
CMD1
...
if CONDITION;then
break
fi
CMDn
...
done
示例
求100以內(nèi)所有偶數(shù)之和,要求循環(huán)遍歷100以內(nèi)的所有正整數(shù)
#!/bin/bash
# filename even.sh
# author:danran
# time is 2017-06-22
declare -i i=0
declare -i sum=0
until [ $i -gt 100 ];do
let i++
if [ $[i%2] -eq 1 ];then
continue
fi
let sum+=$i
done
echo "Even sum:$sum"
創(chuàng)建死循環(huán)
while true洪规;do
循環(huán)體
done
until false印屁;do
循環(huán)體
done
示例
每隔3秒鐘到系統(tǒng)上獲取已經(jīng)登錄的用戶的信息:如果docker登錄了,則記錄于日志中斩例,并退出
read -p "Enter a user name: " username
while true;do
if who | grep "^$username" &> /dev/null;then
break
fi
sleep 3
done
echo "$username logged on" >> /tmp/user.log
法二
#!/bin/bash
#
read -p "Enter a user name: " username
until who | grep "^$username" &> /dev/null;do
sleep 3
done
echo "$username logged on" >> /tmp/user.log
練習(xí)
寫一個(gè)腳本:完成如下任務(wù):
(1)顯示一個(gè)菜單
cpu)show cpu information:
mem)show memory information
disk)show disk information quit)quit
(2)提示用戶選擇選項(xiàng)
(3)顯示用戶選擇的內(nèi)容
進(jìn)一步的:
用戶選擇库车,并顯示完成后不退出腳本;而是提示用戶繼續(xù)選擇顯示其內(nèi)容:直到使用quit方始退出樱拴;
法一
#!/bin/bash
# filename sysinfo.sh
# author:danran
# time is 2017-06-22
cat << EOF
cpu) show cpu information
mem) show memory information
disk)show disk information
quit)quit
============================
EOF
read -p "Enter a option: " option
while [ "$option" != 'cpu' -a "$option" != 'mem' -a "$option" != 'disk' -a "$option" != 'quit' ];do
read -p "Wrong option.Enter again: " option
done
if [ "$option" == 'cpu' ];then
lscpu
elif [ "$option" == 'mem' ];then
cat /proc/meminfo
elif [ "$option" == 'disk' ];then
fdisk -l
else
echo "Quit"
exit 0
fi
條件判斷:case語句
case 變量引用 in
PAT1)
分支1
;;
PAT2)
分支2
;;
...
*)
默認(rèn)分支
;;
easc
- case 支持glob 風(fēng)格的通配符:
*:任意長度任意字符
?:任意單個(gè)字符
[]:指定范圍內(nèi)的任意單個(gè)字符
a|b:a或b
法二
#!/bin/bash
# filename sysinfo.sh
# author:danran
# time is 2017-06-22
cat << EOF
cpu) show cpu information
mem) show memory information
disk)show disk information
quit)quit
============================
EOF
read -p "Enter a option: " option
while [ "$option" != 'cpu' -a "$option" != 'mem' -a "$option" != 'disk' -a "$option" != 'quit' ];do
read -p "Wrong option.Enter again: " option
done
case "$option" in
cpu)
lscpu
;;
mem)
cat /proc/meminfo
;;
disk)
fdisk -l
;;
*)
echo "Quit.."
exit 0
;;
esac
練習(xí):寫一個(gè)腳本,完成如下要求
(1)腳本可接受參數(shù)洋满,start晶乔,stop,restart牺勾,status
(2)如果參數(shù)非此四者之一正罢,提示使用格式后報(bào)錯(cuò)退出
(3)如果是start,則創(chuàng)建/var/lock/subsys/SCRIOT_NAME,并顯示“啟動(dòng)成功”
考慮:如果事先已經(jīng)啟動(dòng)過一次驻民,該如何處理
(4)如果是stop:則刪除/vat/lock/subsys/SCRIPT_NAME,并顯示“停止完成”
考慮:如果事先已經(jīng)停止過了翻具;g該如何處理
(5)如果是restart,則先stop回还,再start裆泳;
考慮:如果本來沒有start,再如何處理
(6)如果是status柠硕,則
如果/var/lock/subsys/SCRIPT_NAME文件存在工禾,則顯示“SCRIPT_NAME is running...”;
如果/var/lock/subsys/SCRIPT_NAME文件不存在,則顯示“SCRIPT_NAME is stopped...”;
其中:SCRIPT_NAME為當(dāng)前腳本名
循環(huán)控制shift命令
shift [n]
用于將參量列表list 左移指定次數(shù)蝗柔,缺省為左移一次闻葵。
- 參量列表list一旦被移動(dòng),最左端的那個(gè)參數(shù)就從列表中刪除癣丧。while到循環(huán)遍歷位置參量列表時(shí)槽畔,常用到shift
- ./doit.sh a b c d e f g h
- ./shfit.sh a b c d e f g h
示例:
doit.sh
#!/bin/bash
# Name:doit.sh
# Purpose:shift through command line arguments
# Usage:doit.sh [args]
while [ $# -gt 0 ] # or (( $# > 0 ))
do
echo $*
shift
done
shift.sh
#!/bin/bash
#step through all the positional parameters
until [ -z "$1" ]
do
echo "$1"
shift
done
echo
特殊用法
- while 循環(huán)的特殊用法(遍歷文件的每一行):
while read line; do
循環(huán)體
done < /PATH/FROM/SOMEFILE
- 依次讀取/PATH/FROM/SOMEFILE文件中的每一行,且將行賦值給變量line
- 練習(xí)
掃描/etc/passwd文件每一行,如發(fā)現(xiàn)GECOS 字段為空胁编,則填充用戶名和單位電話為62985600厢钧,并提示該用戶的GECOS信息修改成功。 - 示例:
#掏呼!/bin/bash
while read passwdline
do
uid=`echo $passwdline | cut -d: -f3`
user=`echo $passwdline | cut -d: -f1`
[ "uid" -ge 1000 ] && echo "$user is common user" || echo "$user is system user"
done < /etc/passwd
unset passwdline uid user
- 雙小括號方法坏快,即((…))格式,也可以用于算術(shù)運(yùn)算
- 雙小括號方法也可以使bash Shell 實(shí)現(xiàn)C 語言風(fēng)格的變量操作
I=10
((I++))
- for循環(huán)的特殊格式:
for (( 控制變量初始化; 條件判斷表達(dá)式; 控制變量的修正表達(dá)式))
do
循環(huán)體
done
- 控制變量初始化:僅在運(yùn)行到循環(huán)代碼段時(shí)執(zhí)行一次
- 控制變量的修正表達(dá)式:每輪循環(huán)結(jié)束會先進(jìn)行控制變量修正運(yùn)算憎夷,而后再做條件判斷
- 示例:求100以內(nèi)的所有正奇數(shù)之和
#莽鸿!/bin/bash
sum=0
for i in {1..100..2};do
let sum+=i
done
echo sum=$sum
#!/bin/bash
for ((sum=0,i=1;i<=100;i+=2 ));do
let sum+=i
done
echo sum=$sum
#!/bin/bash
sum=0;
i=1;
while [ $i -le 100 ];do
let sum+=1
let i+=2
done
echo sum=$sum
2 . 求100以內(nèi)的正整數(shù)之和
#!/bin/bash
declare -i sum=0
for ((i=1;i<=100;i++));do
let sum+=$i
done
echo "Sum:$sum"
3 . 打印九九乘法表:
#!/bin/bash
# filename multi.sh
# author:danran
# time is 2017-06-22
for ((j=1;j<=9;j++));do
for((i=1;i<j;i++));do
echo -e -n "$[i]X$[j]=$[$i*$j]\t"
done
echo
done
select循環(huán)與菜單
select variable in list
do
循環(huán)體命令
done
- select循環(huán)主要用于創(chuàng)建菜單,按數(shù)字順序排列的示菜單項(xiàng)將顯示在標(biāo)準(zhǔn)錯(cuò)誤上,并顯示PS3提示符祥得,等待用戶輸入
- 用戶輸入菜單列表中的某個(gè)數(shù)字兔沃,執(zhí)行相應(yīng)的命令
- 用戶輸入被保存在內(nèi)置變量REPLY中
select與case
- select用是個(gè)無限循環(huán),因此要記住用 break命令退用出循環(huán)级及,或用exit按命令終止腳本乒疏。也可以按ctrl+c退出循環(huán)
- select和經(jīng)常和case聯(lián)合使用
- 與for循環(huán)類似,可以省略inlist饮焦,此時(shí)使用位置參量
- 示例:創(chuàng)建菜單
#怕吴!/bin/bash
PS3="Please choose your menu: "
select menu in work home office exit
do
case $menu in
work)
echo "go work"
;;
home)
echo "go home"
;;
office)
echo "go office"
;;
*)
echo unknow
break
esac
echo your choose is $menu
echo "Your input is $REPLY"
done
信號捕捉trap
- trap ' 觸發(fā)指令' 信號
自定義進(jìn)程收到系統(tǒng)發(fā)出的指定信號后,將執(zhí)行觸發(fā)指令县踢,而不會執(zhí)行原操作 - trap '' 信號
忽略信號的操作 - trap '-' 信號
恢復(fù)原信號的操作 - trap -p
列出自定義信號操作
trap示例
#!/bin/bash
trap 'echo “signal:SIGINT"' int
trap -p \\打印trap自定義命令
for((i=0;i<=10;i++))
do
sleep 1
echo $i
done
trap '' int //int信號設(shè)置為空
trap -p \\打印trap自定義命令
for((i=11;i<=20;i++))
do
sleep 1
echo $i
done
trap '-' int //恢復(fù)int信號的操作
trap -p \\打印trap自定義命令
for((i=21;i<=30;i++))
do
sleep i
echo $i
done