for循环结构
for 循环结构语句
1.for循环结构:
语法:
for 变量名 in 变量取值列表
do
指令...
done
提示:在此结构中“in 变量取值列表”可省略,省略时相当于in “$@”,使用for i 就相当于使用for i in “$@”
2.C语言型for循环结构
for ((exp1;exp2;exp3))
do
指令...
done
使用for循环打印1+...100的方法
[root@web02 28]# sh -v for2.sh module () { eval `/usr/bin/modulecmd bash $*` } #!/bin/bash for ((i=1;i<=100;i++)) do let sum+=i done echo $sum 5050 j=0 while ((j<=100)) do let sumj+=j let j++ done echo $sumj 5050
范例10:计算从1加到100(用C语言型FOR循环实现,2种)
for((i=0;i<=100;i++)) do ((sum=sum+i)) done echo $sum i=0 while ((i<=100)) do ((j=j+i)) i++ done 提示:一般的for循环和while循环可以互相转换使用,即可以实现同样的功能
例子:for和while对比
[root@db02 for]# cat for.sh #!/bin/bash for((i=1;i<=5;i++)) do echo $i done #################################################### i=1 while((i<=5)) do echo $i ((i++)) done
结果:
说明:
(1)程序持续运行多用while,包括守护进程,还有配合read读入处理。
(2)有限次循环多用for,工作中for 使用更多
使用for循环打印1-5(使用for)
[root@web02 28]# sh for.sh 1 2 3 4 5 [root@web02 28]# cat for.sh #!/bin/bash for n in 1 2 3 4 5 do echo $n done
第二种打印方法(使用C语言类型)
[root@web02 28]# sh for.sh a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 [root@web02 28]# cat for.sh #!/bin/bash for n in {0..10} do echo a$n done
常用for例子
使用for循环打印5个ip地址
[root@db02 scripts]# sh for.sh 10.0.0.1 10.0.0.2 10.0.0.3 10.0.0.4 10.0.0.5 [root@db02 scripts]# cat for.sh #!/bin/bash for n in `seq 5` do echo 10.0.0.$n done
使用for循环打印当前目录文件名
[root@db02 scripts]# cat for.sh #!/bin/bash for n in `ls /server/scripts/` do echo $n done
使用for循环,生成随机数
[root@db02 test]# cat ../for.sh #!/bin/bash for((i=1;i<=11;i++)) do mkdir -p test touch ./test/`echo $RANDOM|md5sum|cut -c 1-8`_finished.html done
分库分表备份
[root@db01 scripts]# cat for4.sh MYUSER=root MYPASS=oldboy123 SOCKET=/data/3306/mysql.sock MYCMD="mysql -u$MYUSER -p$MYPASS -S $SOCKET" MYDUMP="mysqldump -u$MYUSER -p$MYPASS -S $SOCKET" for n in `$MYCMD -e "show databases;"|sed '1d'|egrep -v "_schema|mysql"` do $MYDUMP -B $n|gzip >/tmp/${n}_$(date +%F).sql.gz done
实战题:开发脚本实现仅设置sshd rsyslog crond network sysstat开机自启动。
#!/bin/sh LANG=en for name in `chkconfig --list|grep 3:on|awk '{print $1}'` do chkconfig $name off done for name in rsyslog network crond sshd sysstat do chkconfig $name on done
条件与循环等的控制break continue exit return
break continue exit对比
break continue exit 一般用于循环结构中控制循环(for,while,if)的走向
命令 说明 break n n 表示跳出循环的层数,如果省略n表示跳出整个循环 continue n n 表示退到第n层继续循环,如果省略n表示跳过本次循环,忽略本次循环的剩余代码,进入循环的下一次循环。 exit n 退出当前shell程序,n为返回值。n也可以省略,再下一个shell里通过$?接收这个n的值
return n 用于在函数里,作为函数的返回值,用于判断函数执行是否正确
测试:
for((i=0; i<=5; i++)) do if [ $i -eq 3 ] ;then #continue; break; #exit fi echo $i done echo "ok"
break 当i等于3 跳出 直接显示ok
continue 当i等于3 跳过3 直接显示ok。中断本次循环
exit 当i等于3 跳出脚本
使用的脚本案例
[root@web02 28]# sh for5.sh old [root@web02 28]# echo $? 1 [root@web02 28]# sh for5.sh oldboy good [root@web02 28]# echo $? 0 [root@web02 28]# cat for5.sh oldboy(){ if [ "$1" == "oldboy" ];then echo "good" return 0 else return 1 fi } oldboy $1
return 用于在函数中的返回值。
[root@web02 28]# cat re.sh . /server/scripts/28/for5.sh oldboy $1 if [ $? -eq 0 ];then echo "the string you input is [oldboy]" else echo "error" fi [root@web02 28]# cat for5.sh oldboy(){ if [ "$1" == "oldboy" ];then echo "good" return 0 else return 1 fi } [root@web02 28]# sh re.sh error [root@web02 28]# sh re.sh oldboy good the string you input is [oldboy]
范例(生产场景):开发shell脚本实现给服务器临时配置多个别名IP,并可以随时撤销配置的所有IP。
IP地址为:10.0.2.1-10.0.2.16,其中10.0.2.10不能配置。
1.自己做的。
[root@web02 28]# cat ip.sh #!/bin/bash for i in {1..16} do if [ $i -eq 10 ];then continue; fi ip addr add 10.0.2.$i dev eth0:$i label eth0:$i done [root@web02 28]# cat ipdel.sh #!/bin/bash for i in {1..16} do if [ $i -eq 10 ];then continue; fi ip addr del 10.0.2.$i dev eth0:$i label eth0:$i done
2.推荐方法
[root@web02 28]# cat useradd.sh #!/bin/bash [ -f /etc/init.d/functions ] && . /etc/init.d/functions add(){ for ip in {1..16} do if [ $ip -eq 10 ];then continue fi ip addr add 10.0.2.$ip/24 dev eth0:$ip label eth0:$ip &>/dev/null if [ $? -eq 0 ];then action "add $ip" /bin/true else action "add $ip" /bin/false fi done } del(){ for ip in {16..1} do if [ $ip -eq 10 ];then continue fi ip addr del 10.0.2.$ip/24 dev eth0:$ip label eth0:$ip &>/dev/null if [ $? -eq 0 ];then action "del $ip" /bin/true else action "del $ip" /bin/false fi done } read -p "please in put {start|stop}" a case "$a" in start) add RETVAL=$? ;; stop) del RETVAL=$? ;; restart) del sleep 2 add ;; *) echo "Please in put {start|stop}n" ;; esac exit $RETVAL
添加ip的结果
另一种方法:(和第二种区别不大,只是修改了传参)
[root@db02 for]# cat ip.sh #!/bin/sh [ -f /etc/init.d/functions ] && . /etc/init.d/functions RETVAL=0 op(){ if [ "$1" == "del" ] then list=`echo {16..1}` else list=`echo {1..16}` fi for ip in $list do if [ $ip -eq 10 ] then continue fi ip addr $1 10.0.2.$ip/24 dev eth0 label eth0:$ip &>/dev/null if [ $? -eq 0 ] then action "$1 $ip" /bin/true else action "$1 $ip" /bin/false fi done } case "$1" in start) op add RETVAL=$? ;; stop) op del RETVAL=$? ;; restart) op del sleep 2 op add RETVAL=$? ;; *) printf "USAGE:$0 {start|stop|restart}n" esac exit $RETVAL
结果如下。
必须会手写的shell实战案例:
1、开发shell脚本分别实现以脚本传参以及read读入的方式比较2个整数大小。用条件表达式进行判断并以屏幕输出的方式提醒用户比较结果。注意:一共是开发2个脚本。当用脚本传参以及read读入的方式需要对变量是否为数字、并且传参个数不对给予提示。
2、开发shell脚本判断系统剩余内存的大小,如果低于100M就邮件报警给管理员,并且加入系统定时任务每3分钟执行一次检查。
3、开发脚本实现仅设置sshd rsyslog crond network sysstat开机自启动。
4、计算1+2+3...+100之和(使用while,for)
Shell数组
数组介绍
简单的说,数组就是各种数据类型的元素按一定顺序排列的集合。
数组就是把个元素变量或数据用一个名字命名。然后用编号区分它们的变量的集合。这个名字称为数组名,编号称为数组下表。
数组定义与增删改查
方法1:array=(value1 value2 value3....)
1)数组定义
[root@db02 scripts]# array=(1 2 3) #对括号表示是数组,数组元素用“空格”符号分隔开
2)获取数组的长度
[root@db02 scripts]# echo ${array[@]} 1 2 3 [root@db02 scripts]# echo ${array[*]} 1 2 3 #用${#数组名[@或*]} 可以得到数组长度
3)打印数组元素
[root@db02 scripts]# echo ${array[0]} 1 [root@db02 scripts]# echo ${array[1]} 2 #打印数组元素用${数组名[下标]} 下标是从0开始
数组案例
把下面URL定义为数组元素并打印如下元素
http://www.etiantian.org
http://www.taobao.com
http://oldboy.blog.51cto.com
http://10.0.0.7
脚本内容如下
[root@db02 scripts]# cat array.sh #!/bin/bash array=( http://www.etiantian.org http://www.taobao.com http://oldboy.blog.51cto.com http://10.0.0.7 ) for i in ${array[*]} do echo $i done
提示:数组也是变量,因此也适合于前面讲解过的变量的子串处理的功能应用。
参考:
man bash然后搜Arrays
数组的定义:
方法1:array=( value1 value2 value3 ... )
方法2:array=([1]=one [2]=two [3]=three) <==key-value键值对
方法3:array[0]=a array[1]=b array[2]=c
方法4:array=($(ls))
方法1 和方法4是常用方法
数组实践实战例子
批量检查多个网站地址是否正常
要求:
1、shell数组方法实现,检测策略尽量模拟用户访问。
2、每10秒钟做一次所有的检测,无法访问的输出报警。
3、待检测的地址如下
http://www.etiantian.org
http://www.taobao.com
http://oldboy.blog.51cto.com
http://10.0.0.7
分步实现:
1、把URL定义成数组,然后while打印出来。
2、编写URL检查脚本。
3、组合实现整个案例。
第一步:循环打印出URL
#!/bin/bash . /etc/init.d/functions array=( http://www.etiantian.org http://www.taobao.com http://oldboy.blog.51cto.com http://10.0.0.7 ) for((i=0;i<${#array[*]};i++)) do echo ${array[i]} done
第二步:进行命令的拼接
for((i=0;i<${#array[*]};i++)) do ret=`curl -I -s ${array[i]}|egrep "200|302"|wc -l` if [ $ret -eq 1 ];then action "`echo ${array[i]}|awk -F "/" '{print $3}'` is ok" /bin/true else action "`echo ${array[i]}|awk -F "/" '{print $3}'` is not ok" /bin/false echo `echo ${array[i]} is not ok|mail -s "$(date +%F-%S)warning" new_oldboy@163.com` fi done
执行结果:
另一种方法:此方法运用了函数(由老男孩28期李啸宇提供)
[root@db02 scripts]# cat arra.sh #!/bin/sh . /etc/init.d/functions cat >/tmp/a.txt<" sleep 1 echo -ne "b-" done echo -ne ">" echo "" } ping_line(){ while true do arr=($(cat /tmp/a.txt)) for i in ${arr[@]} do curl $i &>/dev/null if [ $? -eq 0 ] then action "$i is OK" /bin/true else action "$i is FALSE" /bin/false fi done limit_time done } main(){ print_line ping_line } main
执行结果:
生成倒计时的脚本:
[root@web02 28]# cat 111.sh limit_time(){ echo "倒计时:" for i in `seq 20 -1 1` do echo -ne ">" sleep 1 echo -ne "b-" done echo -ne ">" echo "" } limit_time
检测URL方法:
第一种:看返回值 curl -I -s --connect-timeout 3 http://oldboy.blog.51cto.com|head -1|egrep -w "200|301|302" &>/dev/null echo $? 第二种:转成行数 curl -I -s --connect-timeout 3 http://oldboy.blog.51cto.com|head -1|egrep -w "200|301|302"|wc -l 第三种: wget -T 3 --spider --tries=2 http://oldboy.blog.51cto.com &>/dev/null echo $?
老男孩老师推荐方法:
[root@db02 scripts]# cat aaa.sh #!/bin/sh ################ #Author:YuHongCong #604419314@qq.com ################ [ -f /etc/init.d/functions ] && . /etc/init.d/functions URLS=( http://www.etiantian.org http://www.taobao.com http://oldboy.blog.51cto.com http://10.0.0.70 ) CHECK_URL(){ wget -T 3 --spider --tries=2 $1 &>/dev/null if [ $? -eq 0 ] then return 0 else return 1 fi } MON_URL(){ for url in ${URLS[*]} do CHECK_URL $url if [ $? -eq 0 ] then action "$url" /bin/true else action "$url" /bin/false fi done } main(){ while true do MON_URL sleep 10 done } main
执行结果:
老男孩推荐:(包含倒计时的方法)
[root@db01 shizhan]# cat oldboy01.sh #!/bin/sh ################ #Author:oldboy #31333741@qq.com ################ [ -f /etc/init.d/functions ] && . /etc/init.d/functions URLS=( http://www.etiantian.org http://www.taobao.com http://oldboy.blog.51cto.com http://10.0.0.70 ) LTIME(){ echo -n "time;" for n in {1..10} do if [ $n -eq 10 ] then echo "start" else echo -n . fi sleep 1 done } CHECK_URL(){ wget -T 3 --spider --tries=2 $1 &>/dev/null if [ $? -eq 0 ] then return 0 else return 1 fi } MON_URL(){ for url in ${URLS[*]} do CHECK_URL $url if [ $? -eq 0 ] then action "$url" /bin/true else action "$url" /bin/false fi done } main(){ while true do LTIME MON_URL sleep 10 done } main
企业案例:打印下面这具有中字母数不大于6的单词
I am oldboy teacher welcome to oldboy training class.
没讲数组之前自己做的:
[root@web02 ~]# cat /server/scripts/28/bash.sh #!/bin/bash for n in `echo I am oldboy teacher welcome to oldboy training class.` do AAA=$( echo $n|wc -c) if [ $AAA -gt 7 ];then continue; fi echo $n done
第一种方法:不使用数组
[root@db02 scripts]# cat 3.sh #!/bin/bash for i in I am oldboy teacher welcome to oldboy training class. do if [ "${#i}" -le 6 ] then echo $i fi done
第二种方法:使用数组
[root@db02 scripts]# cat 3.sh #!/bin/bash array=(I am oldboy teacher welcome to oldboy training class.) for ((i=0;i<${#array[@]};i++)) do if [ "`echo ${array[i]}|wc -L`" -le 6 ] then echo ${array[i]} fi done
第三种方法:命令拼接
echo "I am oldboy teacher welcome to oldboy training class." | awk '{for(i=1;i<=NF;i++){a=length($i);if(a <= 6){print $i}}}'
使用for循环在/oldboy目录下通过随机小写10个字母加固定字符串oldboy批量创建10个html文件,名称例如为:
1
2
3
4
5
6[root@oldboy oldboy]# sh /server/scripts/oldboy.sh [root@oldboy oldboy]# ls coaolvajcq_oldboy.html qnvuxvicni_oldboy.html vioesjmcbu_oldboy.html gmkhrancxh_oldboy.html tmdjormaxr_oldboy.html wzewnojiwe_oldboy.html jdxexendbe_oldboy.html ugaywanjlm_oldboy.html xzzruhdzda_oldboy.html qcawgsrtkp_oldboy.html vfrphtqjpc_oldboy.html
生成10位全小写密码方法
方法1:通过系统环境变量($RANDOM)
[root@db02 ~]# echo $RANDOM 8757 [root@db02 ~]# echo $RANDOM 28279 [root@db02 ~]# echo $RANDOM 22845 man bash 可查帮助随机数范围0-32767
方法2:通过openssl产生随机数
[root@db02 ~]# openssl rand -base64 10 S5IS1GhPchOFPw== [root@db02 ~]# openssl rand -base64 10 Jj2X/g/FyJZqvQ==
因为可能会有大小写以及特殊符号,所以此方法不建议使用
方法3:通过时间生成
[root@db02 ~]# date +%s%N|cut -c 1-10 1469013457 [root@db02 ~]# date +%s%N|cut -c 1-10|tr "[0-9]" "[a-z]" begjabdehb [root@db02 ~]# date +%s%N|cut -c 1-10|tr "[0-9]" "[a-z]" begjabdehe
方法4:系统生成
[root@db02 ~]# head /dev/urandom |cksum 4209252634 2257 [root@db02 ~]# head /dev/urandom |cksum|cut -c 1-10 1779036536 [root@db02 ~]# head /dev/urandom |cksum|cut -c 1-10|tr "[0-9]" "[a-z]" diifejgbdf [root@db02 ~]# head /dev/urandom |cksum|cut -c 1-10|tr "[0-9]" "[a-z]" bgdjgfagfe
方法5:UUID生成
UUID格式是:包含32个16进位数字,以“-”连接号分为五段,形式为8-4-4-4-12的32个字符。UUID理论上的总数为216x8=2128,约等于3.4x1038,也就是说若每秒产生1兆个UUID,要花100亿年才会将所有UUID用完
[root@db02 ~]# cat /proc/sys/kernel/random/uuid 0849fa26-7060-4dbe-a3db-818b5b9cdc62 [root@db02 ~]# cat /proc/sys/kernel/random/uuid 8696f3eb-c092-4692-a1ad-b7de23885252
方法6 :使用mkpasswd专用生成工具(需安装)
[root@db02 ~]# yum install expect -y [root@db02 ~]# mkpasswd -l 8 hxL1aG7/ [root@db02 ~]# mkpasswd -l 8 2VU(t1qb [root@db02 ~]# mkpasswd -l 8 pJ0{H5vx 用法:mkpasswd(args)[用户] 参数: - l #(密码的长度,默认= - c) - d #(min #数字,默认= 2) - c #(min #的小写字符,默认= 2) - c #(min #大写字符,默认= 2) - s #(min #的特殊字符,默认= 1) - v(详细显示passwd交互) - p学监(程序设置密码,默认= passwd) mkpasswd -l 10 -C 0 -d 0 -s 0
方法7:使用awk生成(用处不大)
[root@db02 ~]# awk 'BEGIN{srand();for(j=0;j<2;j++){for(i=0;i<10;i++){printf("%c",rand()*10+97)}print}}' fhbcgdaifd bebcebdgch
生成文件
方法1:
#!/bin/sh dir=/oldboy for n in {1..10} do [ ! -d $dir ] && mkdir $dir touch $dir/$(mkpasswd -l 10 -C 0 -d 0 -s 0)_oldboy.html done
方法2:
[ -d /oldboy ] || mkdir /oldboy i=0 while ((i < 10)) do ((i++)) for n in `mkpasswd -C 0 -d 0 -s 0` do touch /oldboy/${n}_oldboy.html done done
将文件名中包含oldboy全部修改为oldgirl,并且html改成大写
[root@db01 shizhan]# cat oldboy04.sh #!/bin/sh dir=/oldboy [ -d $dir ]||mkdir -p $dir cd $dir for file in `ls *.html` do mv $file `echo $file|sed -e 's#oldboy#oldgirl#g;s#html#HTML#g'` done
还可以使用rename
[root@db01 oldboy]# rename "oldgirl" "oldboy" *.HTML [root@db01 oldboy]# rename "HTML" "html" *.HTML [root@db01 oldboy]# ls -l 总用量 0 -rw-r--r-- 1 root root 0 7月 15 18:02 oldboy_ammkzjlpku.html -rw-r--r-- 1 root root 0 7月 15 18:02 oldboy_biedqiinlp.html -rw-r--r-- 1 root root 0 7月 15 18:02 oldboy_dkyhxztemc.html -rw-r--r-- 1 root root 0 7月 15 18:02 oldboy_euccgeydmq.html -rw-r--r-- 1 root root 0 7月 15 18:02 oldboy_mrhwpsssqk.html -rw-r--r-- 1 root root 0 7月 15 18:02 oldboy_sueeqfnxsc.html -rw-r--r-- 1 root root 0 7月 15 18:02 oldboy_uymykndtei.html -rw-r--r-- 1 root root 0 7月 15 18:02 oldboy_wwmdvnniww.html -rw-r--r-- 1 root root 0 7月 15 18:02 oldboy_xjqjkgxpew.html -rw-r--r-- 1 root root 0 7月 15 18:02 oldboy_zuegqfjdsw.html
案例:批量创建10个系统帐号oldboy01-oldboy10并设置密码(密码为随机8位字符串)。
[root@db02 ~]# cat 3.sh #!/bin/sh [ -f /etc/init.d/functions ]&& source /etc/init.d/functions [ $UID -ne 0 ]&&{ echo "Ples sudo su - root" exit 1 } for user in gongli{01..10} do word=$(grep "b$userb" /etc/passwd|wc -l) if [ $word -eq 1 ];then action "Useradd $user already exists" /bin/false continue fi pass=$(echo $RANDOM|md5sum|cut -c 1-8) useradd $user && echo "$user:$pass"|tee >>/tmp/userlist.log done chpasswd < /tmp/userlist.log
比第一种加了一个正确选项
[root@db02 ~]# cat add.sh #!/bin/sh [ -f /etc/init.d/functions ]&& source /etc/init.d/functions [ $UID -ne 0 ]&&{ echo "Ples sudo su - root" exit 1 } for user in xu{01..10} do word=$(grep "b$userb" /etc/passwd|wc -l) if [ $word -eq 1 ];then action "Useradd $user already exists" /bin/false continue fi pass=$(echo $RANDOM|md5sum|cut -c 1-8) useradd $user && echo "$pass"|passwd --stdin $user &>/dev/null RETVAL=$? if [ $RETVAL -eq 0 ];then action "Useradd $user IS OK" /bin/true fi echo -e "$usert$pass" >>/tmp/user.txt done
测试结果:
企业常见面试题:
已知下面的字符串是通过RANDOM随机数变量md5sum|cut-c 1-8截取后的结果,请破解这些字符串对应的md5sum前的RANDOM对应数字?
21029299
00205d1c
a3da1677
1f6d12dd
890684b
方法一:
#!/bin/bash . /etc/init.d/functions MD5PASS=( 21029299 00205d1c a3da1677 1f6d12dd 890684b ) for ((n=0;n<=32767;n++)) do for((i=0;i<${#MD5PASS[*]};i++)) do md5=`echo $n | md5sum|cut -c 1-8` if [ "$md5" == ${MD5PASS[$i]} ] then echo "$n" "${MD5PASS[$i]} " fi done done
方法二:
[root@openvpn-server ~]# cat md5sum.sh #!/bin/sh a=( 21029299 00205d1c a3da1677 1f6d12dd 890684b ) for i in `seq 32767` do source=`echo $i|md5sum|cut -c 1-8` for j in ${a[@]} do if [ $source == $j ];then echo $source "-->" $i fi done done
方法3:
[root@m01 ~]# cat mianshiti6.sh #!/bin/bash mima=( 21029299 00205d1c a3da1677 1f6d12dd 890684b ) for i in {1..32767} do num=`echo $i | md5sum | cut -c -8` for n in ${mima[*]} do if [ "$num" == "$n" ] then echo "$i match $n" continue fi done done
相关文章:
- Shell 变量及函数讲解 [2]
- 老男孩Shell企业面试题30道 [答案]
- Shell 基础介绍 [1]
- Kubernetes 1.14 二进制集群安装