循環
循環執行
>將某代碼段重複運行多次
>重複運行多少次
>>循環次數事先已知
>>循環次數事先未知>有進入條件和退出條件
for, while, until
for循環
- 用法:
for NAME [in WORDANDS; S ...]; do COMMdone
for 變量名 in 列表;do 循環體 done
- 執行機制:
依次將列表中的元素賦值給“變量名”; 每次賦值後即執 行一次循環體; 直到列表中的元素耗盡,循環結束
-
列表生成方式:
直接給出列表
整數列表:
> {start..end}
>$(seq [start [step]] end)返回列表的命令
>$(COMMAND)使用glob,如:.sh
變量引用; $@, $ - 練習
1、判斷/var/目錄下所有文件的類型 --->在做一次
#!/bin/bash
for i in /var/* ;do
if [ -b $i ];then
echo "$i是塊設備"
elif [ -c $i ] ;then
echo "$i是字符設備"
elif [ -f $i ];then
echo "$i是普通文件"
elif [ -h $i ];then
echo "$i是符號鏈接文件"
elif [ -p $i ];then
echo "$i是管道文件"
elif [ -S $i ];then
echo "$i是套接字文件"
elif [ -d $i ];then
echo "$i是目錄文件"
else
echo "文件或目錄不存在"
fi
done
2、添加10個用戶user1-user10,密碼爲8位隨機字符,並且把生成的用戶名及密碼保存到/app/newuser.txt文件中
#!/bin/bash
for i in `seq 1 5` ; do
username=user$i
useradd $username
password=`openssl rand -base64 10 | head -c 8`
echo $password | passwd --stdin $username &> /dev/null
echo $username $password >> /app/password.txt
done
echo "ok"
3、/etc/rc.d/rc3.d目錄下分別有多個以K開頭和以S開頭的文件 ;分別讀取每個文件,以K開頭的輸出爲文件加stop,以S開頭的輸 出爲文件名加start,如K34filename stop S66filename start --->在做一次
#!/bin/bash
for i in /etc/rc.d/rc3.d/[SK]* ;do
if [ $(basename $i | cut -c1) == "K" ] ;then
echo "`basename $i` stop"
else
echo "`basename $i` start"
fi
done
4、編寫腳本,提示輸入正整數n的值,計算1+2+...+n的總和
#!/bin/bash
read -p "Please input a positive integer: " num
for i in `seq 1 $num` ; do
let sum+=$i
done
echo $sum
5、計算100以內所有能被3整除的整數之和
#!/bin/bash
for i in `seq 0 3 100` ; do
let sum+=$i
done
echo $sum ------>1683
6、計算100以內所有不能被3整除的整數之和
for i in `seq 1 100` ; do
if [ "$[i%3]" -ne 0 ] ; then
let sum+=$i
fi
done
echo $sum ------>3376
7、編寫腳本,提示請輸入網絡地址,如192.168.0.0,判斷輸入的網段中主機在線狀態
#!/bin/bash
> /app/ip.log
read -p "Please input the network(eg:172.18.1.0): " network
[[ "$network" =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]] || { echo "Please input a legal IP " ; exit 250; } ----->**一定要注意250後的分號,機器容易忽略的位置**
net=`echo $network | cut -d. -f 1-3`
for i in {1..254} ; do
{
if ping -c 1 -w 1 $net.$i &> /dev/null ; then
echo $net.$i is up | tee -a /app/ip.log
else
echo $net.$i is down
fi
}&
done
wait
8、打印九九乘法表
#!/bin/bash
for i in `seq 1 9` ; do
for j in `seq $i` ; do
echo -e "${j}x${i}=$[i*j]\t\c"
done
echo
done
9、在/testdir目錄下創建10個html文件,文件名格式爲數字N(從1到10)加隨機8個字母,如:1AbCdeFgH.html
#!/bin/bash
for i in {1..10} ; do
touch /testdir/"$i"`openssl rand -base64 100 | tr -dc '[:alpha:]' | head -c 8`.html
done
10、打印等腰三角形
#!/bin/bash
read -p "Please enter a number: " x
for i in `seq $x` ; do
let space=$x-$i
let xing=2*$i-1
for j in `seq $space` ; do
echo -e " \c"
done
for k in `seq $xing` ; do
echo -e "*\c"
done
echo
done
until循環
- 用法
until CONDITION; do 循環體 done 進入條件: CONDITION 爲false 退出條件: CONDITION 爲true
循環控制語句continue
- continue用於循環體中
- continue [N]:提前結束第N層的本輪循環,而直接進入下一輪判斷;最內層爲第1層
- 用法:
while CONDTIITON1; do CMD1 ... if CONDITION2; then continue fi CMDn ... done
循環控制語句break
- break用於循環體中
- break [N]:提前結束第N層循環,最內層爲第1層
- 用法:
while CONDTIITON1; do CMD1 ... if CONDITION2; then break fi CMDn ... done
循環控制shift命令
- shift [n]
- 用於將參量列表 list 左移指定次數,缺省爲左移一次。
- 參量列表 list 一旦被移動,最左端的那個參數就從列表中刪 除。while 循環遍歷位置參量列表時,常用到 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
for 特殊用法
- 雙小括號方法,即((...))格式,也可以用於算術運算
- 雙小括號方法也可以使bash Shell實現C語言風格的變量操作
I=10
((I++)) - 控制變量初始化:僅在運行到循環代碼段時執行一次
- 控制變量的修正表達式:每輪循環結束會先進行控制變量修正運算,而後再做條件判斷
-
用法
for ((控制變量初始化;條件判斷表達式;控制變量的修正表達式)) do 循環體 done for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done Arithmetic for loop. Equivalent to (( EXP1 )) while (( EXP2 )); do COMMANDS (( EXP3 )) done
示例:
1、求1-100的和
寫法1
#!/bin/bash
sum=o
for ((i=1;i<=100;i++)) ; do
let sum+=i
done
echo sum=$sum
寫法2
for ((sum=0,i=1;i<=100;i++)) ; do
let sum+=i
done
echo sum=$sum
2、求1-100中 3 的整數倍的和
用for寫法
for ((sum=0,i=0;i<=100;i+=3)) ; do
let sum+=i
done
echo sum=$sum
用while寫法
sum=0
i=0
while [ "$i" -le 100] ; do
let sum+=i
let i+=3
done
echo sum=$sum
3、打印9x9表
for ((i=1;i<=9;i++)) ; do
for ((j=1;j<=i;j++)) ; do
echo -ne "${j}x${i}=$[$i*$j]\t" ;
done
echo
done
- 練習
1、每隔3秒鐘到系統上獲取已經登錄的用戶的信息;如果發 現用戶hacker登錄,則將登錄時間和主機記錄於日誌 /var/log/login.log中,並退出腳本 --->在做一次
#!/bin/bash
username=cent
{
while true ;do
if who | egrep "^\b$username\b" &> /dev/null ;then
who | egrep "^\b$username\b" >> /var/log/login.log
echo "$username 已登錄"
echo "fuck ,go out my system" | write $username
else
echo "$username 已下線"
fi
sleep 3
done
}
2、隨機生成10以內的數字,實現猜字遊戲,提示比較大或小 ,相等則退出
suiji=`echo $[$RANDOM%10+1]`
read -p "Please input a number in 1-10: " num
until [[ "$num" -eq "$suiji" ]] ; do
if [[ "$num" -lt "$suiji" ]] ; then
read -p "less than random: " num
else
read -p "much than random: " num
fi
done
echo -e "\e[32mCongratulations! The random is $suiji!\e[37m"
3、用文件名做爲參數,統計所有參數文件的總行數
4、用二個以上的數字爲參數,顯示其中的最大值和最小值
while 循環
-
用法
while CONDITION; do 循環體 done
CONDITION:循環控制條件;進入循環之前,先做一次判 斷;每一次循環之後會再次做判斷;條件爲“true”,則執行 一次循環;直到條件測試狀態爲“false”終止循環
因此:CONDTION一般應該有循環控制變量;而此變量的值 會在循環體不斷地被修正
進入條件:CONDITION爲true
退出條件:CONDITION爲false - 創建無線循環
while true; do 循環體 done
-
while循環的特殊用法
遍歷文件的每一行
while read line; do 循環體 done < /PATH/FROM/SOMEFILE 依次讀取/PATH/FROM/SOMEFILE文件中的每一行, 且將行賦值給變量line 示例: 掃描/etc/passwd文件每一行,如發現GECOS字段爲空,則填 充用戶名和單位電話爲62985600,並提示該用戶的GECOS信 息修改成功。
- 練習
1、編寫腳本,求100以內所有正奇數之和
#!/bin/bash
i=1
while [ "$i" -le 100 ] ; do
if [ $[$i%2] -ne 0 ] ; then
let sum+=$i
fi
let i++
done
echo $sum
2、編寫腳本,提示請輸入網絡地址,如192.168.0.0,判斷輸入的網段中主機在線狀態,並統計在線和離線主機各多少
#!/bin/bash
read -p "Please input the network(eg:172.18.0.1): " network
[[ "$network" =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-9])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-9])$ ]] || { echo "Please input a legal IP " ; exit 250 ; }
net=`echo $network | cut -d. -f 1-3`
i=1
up=0
down=0
while [ "$i" -le 254 ] ; do
ping -c 1 -w 1 $net.$i &> /dev/null && { echo $net.$i is up ; let ++up ; } || { echo $net.$i is down ; let down++ ; }
let i++
done
wait
echo i=$i
echo up host is $up
echo down host is $down
3、編寫腳本,打印九九乘法表
#!/bin/bash
i=1
j=1
while [ $i -le 9 ] ;do
while [ $j -le $i ] ;do
echo -ne "${j}x${i}=$[i*j]\t"
let j+=1
done
let i+=1
j=1
echo
done
4、編寫腳本,利用變量RANDOM生成10個隨機數字,輸出 這個10數字,並顯示其中的最大值和最小值
#!/bin/bash
let i=0,min=max=$RANDOM
echo "$min "
while [ $i -lt 9 ];do
ran=$RANDOM
echo "$ran "
if [ $ran -ge $max ];then
let max=ran
fi
if [ $ran -le $min ];then
let min=ran
fi
let i+=1
done
echo "最大值是 $max ,最小值是 $min"
5、編寫腳本,實現打印國際象棋棋盤
#!/bin/bash
let x=y=1
h=8
while [ $x -le $h ];do
while [ $y -le $h ];do
if [ $[(x+y)%2] -eq 0 ] ;then
echo -en "\033[47m \033[0m"
else
echo -en "\033[40m \033[0m"
fi
let y+=1
done
echo
let x+=1,y=1
done
6、後續六個字符串:efbaf275cd、4be9c40b8b、 44b2395c46、f8c8873ce0、b902c16c8b、ad865d2f63 是通過對隨機數變量RANDOM隨機執行命令:echo $RANDOM|md5sum|cut –c1-10 後的結果,請破解這些字符串對應的RANDOM值
#!/bin/bash
key_num_array=(efbaf275cd 4be9c40b8b 44b2395c46 f8c8873ce0 b902c16c8b ad865d2f63)
for true_num in `seq 0 65535`;do
key_num=`echo $true_num | md5sum | cut -c 1-10`
for num in ${key_num_array[*]}; do
if [ "$key_num" == "$num" ];then
echo "$num --> $true_num"
fi
done
done
7 、檢測httpd服務是否處於開啓狀態,如果處於關閉狀態,即刻開啓服務
#!/bin/bash
sleeptime=30
while true ; do
if killall -0 httpd &> /dev/null ; then
true
else
service httpd restart
time=`date +"%F %T"`
echo "At $time httpd is restart" >> /app/httpd.log
fi
sleep $sleeptime
done
8、檢測磁盤利用率,如果大於80,就發出警報,每5分鐘檢測一次
第一種方法:
while true ; do
df -h | grep "/dev/sd" | while read disk ; do
per=`echo $disk | sed -r 's/.* (.*)%.*/\1/'`
part=`echo $disk | cut -d" " -f1`
[ "$per" -gt 80 ] && echo "$part will be full,over 80%"
done
sleep 300
done
第二種方法-做成計劃任務調用腳本,腳本內容如下
used=10
df -h | grep "/dev/sd" | while read disk ; do
per=`echo $disk | sed -r 's/.* (.*)%.*/\1/'`
part=`echo $disk | cut -d" " -f1`
[ "$per" -gt "$used" ] && echo "$part will be full,over ${used}%"
done
select循環與菜單
- select 循環主要用於創建菜單,按數字順序排列的 菜單項將顯示在標準錯誤上,並顯示 PS3 提示符,等待用戶輸入
- 用戶輸入菜單列表中的某個數字,執行相應的命令
- 用戶輸入被保存在內置變量 REPLY 中
- 用法
select variable in list do 循環體命令 done
- select 是個無限循環,因此要記住用 break 命令退 出循環,或用 exit 命令終止腳本。也可以按 ctrl+c 退出循環
- select 經常和 case 聯合使用
- 與 for 循環類似,可以省略 in list,此時使用位置 參量
示例:
1、用while完成的菜單
#!/bin/bash
cat <<EOF
1 yxrs
2 gbjd
3 lzjd
4 lamian
5 huimian
6 yangroutang
7 quit
EOF
while read -p "Please choose the menu number: " menu ; do
case $menu in
1|2)
echo The price is 20
;;
3|6)
echo The price is 25
;;
4|5)
echo The price is 15
;;
7)
break
;;
*)
echo "Please choose again"
;;
esac
done
2、用select 完成
PS3="Please choose the menu number: "
select menu in gbjd yxrs lamian huimian baoyu quit ; do
case $menu in
gbjd|yxrs)
echo The price is 25
;;
lamian|huimian)
echo The price is 15
;;
baoyu)
echo The price is 100
;;
quit)
break
;;
*)
echo "Try choose again"
;;
esac
done
3、select 與 $REPLY 配合
PS3="Please choose the menu number: "
select menu in gbjd yxrs lamian huimian baoyu quit ; do
case $REPLY in
1|2)
echo The price is 25
;;
3|4)
echo The price is 15
;;
5)
echo The price is 100
;;
6)
break
;;
*)
echo "Try choose again"
;;
esac
done
trap 信號捕捉
- trap '觸發指令' 信號 自定義進程收到系統發出的指定信號後,將執行觸發指令,而不會執行原操作
-
用法
trap '' 信號
>忽略信號的操作trap '-' 信號
>恢復原信號的操作trap -p
>列出自定義信號操作 - trap示例
#!/bin/bash
trap 'echo “signal:SIGINT"' int
trap -p
for((i=0;i<=10;i++))
do
sleep 1
echo $i
done
trap '' int
trap -p
for((i=11;i<=20;i++))
do
sleep 1
echo $i
done
trap '-' int
trap -p
for((i=21;i<=30;i++))
do
sleep 1
echo $i
done
#!/bin/bash
trap `echo Do not break` INT
fo i in {1..10} ; do
echo $i
sleep 0.5
done