###课程目标:
列表for循环:用于将一组命令执行已知的次数,下面给出了for循环语句的基本格式:
for variable in {list}
do
command
command
…
done
或者
for variable in a b c
do
command
command
done
语法结构举例说明:
x1045 for var in {1..10};do echo $var;done
1046 for var in 1 2 3 4 5;do echo $var;done
1047 for var in `seq 10`;do echo $var;done
1048 for var in $(seq 10);do echo $var;done
1049 for var in {0..10..2};do echo $var;done
1050 for var in {2..10..2};do echo $var;done
1051 for var in {10..1};do echo $var;done
1052 for var in {10..1..-2};do echo $var;done
1055 for var in `seq 10 -2 1`;do echo $var;done
不带列表的for循环执行时由用户指定参数和参数的个数,下面给出了不带列表的for循环的基本格式:
xxxxxxxxxx
for variable
do
command
command
…
done
语法结构举例说明:
xxxxxxxxxx
#!/bin/bash
for var
do
echo $var
done
echo "脚本后面有$#个参数"
xxxxxxxxxx
for(( expr1; expr2; expr3 ))
do
command
command
…
done
expr1:定义变量并赋初值
expr2:决定是否进行循环(条件)
expr3:决定循环变量如何改变
语法结构举例说明:
xxxxxxxxxx
1068 for ((i=1;i<=5;i++));do echo $i;done
1069 for ((i=1;i<=10;i+=2));do echo $i;done
1070 for ((i=2;i<=10;i+=2));do echo $i;done
demo1:计算1到100的奇数之和,方法不止一种
xxxxxxxxxx
方法1:
#!/bin/bash
sum=0
for i in {1..100..2}
do
sum=$[$i+$sum]
done
echo "1-100的奇数和为:$sum"
方法2:
#!/bin/bash
sum=0
for ((i=1;i<=100;i+=2))
do
let sum=$i+$sum
done
echo "1-100的奇数和为:$sum"
方法3:
#!/bin/bash
sum=0
for ((i=1;i<=100;i++))
do
if [ $[$i%2] -ne 0 ];then
let sum=$sum+$i
fi
或者
test $[$i%2] -ne 0 && let sum=$sum+$i
done
echo "1-100的奇数和为:$sum"
方法4:
sum=0
for ((i=1;i<=100;i++))
do
if [ $[$i%2] -eq 0 ];then
continue
else
let sum=$sum+$i
fi
done
echo "1-100的奇数和为:$sum"
变量的调用:
$变量名 ${变量名}
$a ${a}
四则运算:
$((2%2)) $[2/2] let n=$i+$sum
命令优先执行:
$(命令) `命令`
循环控制: continue:继续。表示循环体内下面的代码不执行,重新开始下一次循环 break:打断。马上停止执行本次循环,执行循环体后面的代码 exit:表示直接跳出程序
demo2:输入一个正整数,判断是否为质数(素数) 质数:只能被1和它本身整除的数叫质数。 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
xxxxxxxxxx
思路:
1、如果能被其他数整除就不是质数——>$num%$i 是否等于0
2、如果输入的数是1或者2取模根据上面判断又不符合,所以先排除1和2
3、测试序列从2开始,输入的数是4——>得出结果$num不能和$i相等,并且$num不能小于$i
xxxxxxxxxx
#!/bin/bash
read -p "请输入一个正整数字:" number
[ $number -eq 1 ] && echo "$number不是质数" && exit
[ $number -eq 2 ] && echo "$number是质数" && exit
for i in `seq 2 $[$number-1]`
do
[ $[$number%$i] -eq 0 ] && echo "$number不是质数" && exit
done
echo "$number是质数" && exit
demo3:批量加5个新用户,以u1到u5命名,并统一加一个新组,组名为class,统一改密码为123
xxxxxxxxxx
#!/bin/bash
grep -w class /etc/group &>/dev/null
test $? -ne 0 && groupadd class
或者
groupadd class &>/dev/null
for ((i=1;i<=5;i++))
do
useradd -G class u$i && echo 123|passwd --stdin u$i
done
1、批量新建5个用户stu1~stu5,要求这几个用户的家目录都在/rhome.提示:需要判断该目录是否存在
xxxxxxxxxx
2、写一个脚本,局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里(如果例举整个网段的254个IP花的时间比较长,可以只分类10个ip192.168.1.10~20) 这只是一个局域网内机器检查通讯的一个思路。
xxxxxxxxxx
3、输入一个年份,判断是否是润年(能被4整除但不能被100整除,或能被400整除的年份即为闰年。)
xxxxxxxxxx
#!/bin/bash
read -p "Please input year:(2017)" year
if [ $[$year%4] -eq 0 -a $[$year%100] -ne 0 ];then
echo "$year is leap year"
elif [ $[$year%400] -eq 0 ];then
echo "$year is leap year"
else
echo "$year is not leap year"
fi
条件为真就退出循环;条件为假就死循环
xxxxxxxxxx
until expression [ 1 -eq 1 ] (( 1 >= 1 ))
do
command
command
...
done
示例1:使用until打印1-5
xxxxxxxxxx
示例2:使用until批量创建用户,用户user01~user03,并且家目录为/rhome/user01...
xxxxxxxxxx
#!/bin/bash
#create users
#判断用户的家目录/rhome是否存在,不存在创建它
dir=/rhome
[ ! -d $dir ] && mkdir $dir -p
i=1
until [ $i -gt 3 ]
do
useradd -d $dir/user0$i user0$i && echo 123|passwd --stdin user0$i && let i++
done
条件为真就进入死循环;条件为假就退出循环
xxxxxxxxxx
while expression [ 1 -eq 1 ] (( 1 > 2 ))
do
command
command
...
done
xxxxxxxxxx
示例:
写一个30秒同步一次时间同步服务器10.1.1.1的脚本,如果同步失败,则进行邮件报警,每次失败都报警;同步成功,也进行邮件通知,但是成功100次才通知一次。
xxxxxxxxxx
分析:
1. 计划任务时间最小是分钟,所以不能直接使用crontab完成,那么需要写脚本
2. 脚本每隔30s同步,该脚本是死循环,并且sleep 30来控制间隔
#!/bin/bash
#ntpdate
count=0
ip=10.1.1.1
while true
do
rdate -s $ip &>/dev/null
if [ $? -ne 0 ];then
echo "时间同步失败,请检查..." |mail -s "check system times" root@MissHou.itcast.cc
else
let count++
if [ $[$count%100] -eq 0 ];then
echo "时间同成功" |mail -s "check system times" root@MissHou.itcast.cc
count=0
fi
fi
sleep 30
done
或者
#!/bin/bash
#ntpdate
count=0
ip=10.1.1.1
while true
do
rdate -s $ip &>/dev/null
if [ $? -ne 0 ];then
echo "时间同步失败,请检查..." |mail -s "check system times" root@MissHou.itcast.cc
else
let count++
[ $[$count%100] -eq 0 ] && echo "时间同成功" |mail -s "check system times" root@MissHou.itcast.cc && count=0
fi
sleep 30
done
总结:
用至少三种方法打印1~5和5-1
xxxxxxxxxx
xxxxxxxxxx
bash默认有一个$RANDOM的变量 默认是0~32767。使用set |grep RANDOM 查看上一次产生的随机数
echo $RANDOM
产生0~1之间的随机数
echo $[$RANDOM%2]
产生0~2之间的随机数
echo $[$RANDOM%3]
产生0~3之间的随机数
echo $[$RANDOM%4]
。。。。
产生0~9内的随机数
echo $[$RANDOM%10]
产生0~100内的随机数
echo $[$RANDOM%101]
产生50-100之内的随机数
echo $[$RANDOM%51+50]
产生三位数的随机数
echo $[$RANDOM%900+100]
xxxxxxxxxx
#!/bin/bash
#create phone num file
for ((i=1;i<=1000;i++))
do
n1=`echo $[$RANDOM%10]`
n2=`echo $[$RANDOM%10]`
n3=`echo $[$RANDOM%10]`
n4=`echo $[$RANDOM%10]`
n5=`echo $[$RANDOM%10]`
n6=`echo $[$RANDOM%10]`
n7=`echo $[$RANDOM%10]`
n8=`echo $[$RANDOM%10]`
echo "139$n1$n2$n3$n4$n5$n6$n7$n8" |tee -a phonenum.txt
done
或者
#!/bin/bash
count=0
while true
do
n1=`echo $[$RANDOM%10]`
n2=`echo $[$RANDOM%10]`
n3=`echo $[$RANDOM%10]`
n4=`echo $[$RANDOM%10]`
n5=`echo $[$RANDOM%10]`
n6=`echo $[$RANDOM%10]`
n7=`echo $[$RANDOM%10]`
n8=`echo $[$RANDOM%10]`
echo "139$n1$n2$n3$n4$n5$n6$n7$n8" |tee -a phonenum.txt && let count++
if [ $count -eq 1000 ];then
break
fi
done
思路:
xxxxxxxxxx
#!/bin/bash
for ((i=1;i<=5;i++))
do
file=phonenum.txt
line=`cat phonenum.txt |wc -l`
luckline=$[$RANDOM%$line+1]
phone=`cat phonenum.txt|head -$luckline|tail -1`
echo "幸运观众为:${phone:0:3}****${phone:7:4}"
#sed -i "/$phone/d" $file
done
或者
#!/bin/bash
# choujiang
phone=phonenum.txt
for ((i=1;i<=5;i++))
do
num=`wc -l phonenum.txt |cut -d' ' -f1`
line=`echo $[$RANDOM%$num+1]`
luck=`head -$line $phone |tail -1`
sed -i "/$luck/d" $phone
echo "幸运观众是:139****${luck:7:4}"
done
思路:
xxxxxxxxxx
#!/bin/bash
#crate user and set passwd
#产生一个保存用户名和密码的文件
echo user0{1..3}:itcast$[$RANDOM%9000+1000]#@~|tr ' ' '\n'>> user_pass.file
#循环创建5个用户
for ((i=1;i<=5;i++))
do
user=`head -$i user_pass.file|tail -1|cut -d: -f1`
pass=`head -$i user_pass.file|tail -1|cut -d: -f2`
useradd $user
echo $pass|passwd --stdin $user
done
或者
for i in `cat user_pass.file`
do
user=`echo $i|cut -d: -f1`
pass=`echo $i|cut -d: -f2`
useradd $user
echo $pass|passwd --stdin $user
done
#!/bin/bash
#crate user and set passwd
#产生一个保存用户名和密码的文件
echo user0{1..3}:itcast$[$RANDOM%9000+1000]#@~|tr ' ' '\n'|tr ':' ' ' >> user_pass.file
#循环创建5个用户
while read user pass
do
useradd $user
echo $pass|passwd --stdin $user
done < user_pass.file
一个循环体内又包含另一个完整的循环结构,称为循环的嵌套。在外部循环的每次执行过程中都会触发内部循环,直至内部完成一次循环,才接着执行下一次的外部循环。for循环、while循环和until循环可以相互嵌套。
demo1:打印如下图案
xxxxxxxxxx
for ((i=1;i<=5;i++))
do
for ((j=1;j<=5;j++))
do
echo world
done
echo hello
done
1
12
123
1234
12345
y轴
x轴
#!/bin/bash
for ((y=1;y<=5;y++))
do
for ((x=1;x<=$y;x++))
do
echo -n $x
done
echo
done
#!/bin/bash
for ((y=1;y<=5;y++))
do
x=1
while [ $x -le $y ]
do
echo -n $x
let x++
done
echo
done
while
until
demo2:打印如下图案
xxxxxxxxxx
5
54
543
5432
54321
#!/bin/bash
y=1
until (( $y >5 ))
do
x=1
while (( $x <= $y ))
do
echo -n $[6-$x]
let x++
done
echo
let y++
done
54321
5432
543
54
5
课堂练习:打印九九乘法表(三种方法)
xxxxxxxxxx
1
12
123
1234
12345
#!/bin/bash
for ((y=1;y<=9;y++))
do
for ((x=1;x<=$y;x++))
do
echo -ne "$x*$y=$[$y*$x]\t"
done
echo
echo
done
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
xxxxxxxxxx
普通变量定义:
变量名=值 shell变量默认可以赋予任何类型
$变量名 ${变量名} ${变量名:从第几个字符开始:截取几个字符}
unset 变量名
交互式:
read 变量名
-p
-t
-s
-n
数组定义:
array=(var1 var2 var3 ...)
array[0]=var1
array[1]=var2
array[2]=var3
普通数组:数组的索引是整数
获取数组里的元素:
${array[*]}
${array[2]}
${array[@]:1:2}
${!array[@]} 获取数组的索引号(下标)
${#array[@]} 获取数组索引号的个数
定义有类型的变量:
declare
-i
-x
-a
-A
定义关联数组
关联数组:索引是字符串
1185 declare -a
1186 declare -A
1187 declare -A array1
1188 array1=([linux]=1 [java]=2 [C]= )
1189 echo ${array1[@]}
1190 echo ${!array1[@]}
1191 declare -A array2
1192 array2[Aa]=1
1193 array2[Bb]=2
1194 echo ${array2[*]}
1195 let array1[linux]++
1196 echo ${array1[linux]}
1197 let array1[C]++
1198 echo ${array1[C]}
1199 let array1[C]++
1200 echo ${array1[C]}
1201 let array1[php]++
1202 echo ${array1[php]}
1203 let array1[php]++
1204 echo ${array1[php]}
1205 declare -A
1206 let array2[Cc]++
1207 declare -A
1208 let array2[Cc]++
1209 declare -A
1210 declare -a
1211 let array[3]++
1212 declare -a
1213 let array[3]++
1214 declare -a
xxxxxxxxxx
for:
列表循环、非列表循环、类C风格 循环次数已知
while:
条件为真,进入循环,条件为假,退出循环 循环次数跟条件有关
until:
条件为假,进入循环,条件为真,退出循环 循环次数跟条件有关
xxxxxxxxxx
exit 退出整个程序
break 结束当前循环,或跳出本层循环
continue 忽略本次循环剩余的代码,直接进行下一次循环
shift 使位置参数向左移动,默认移动1位,可以使用shift 2
以下脚本都能够实现用户自定义输入数字,然后脚本计算和:
[root@MissHou shell03]# cat shift.sh
#!/bin/bash
sum=0
while [ $# -ne 0 ]
do
let sum=$sum+$1
shift
done
echo sum=$sum
[root@MissHou shell03]# cat for3.sh
#!/bin/bash
sum=0
for i
do
let sum=$sum+$i
done
echo sum=$sum
:
true
false
写一个脚本,将跳板机上yunwei用户的公钥推送到局域网内可以ping通的所有机器上
10.1.1.1~10.1.1.254
xxxxxxxxxx
#!/bin/bash
#push publickey to aap-servers
#将局域网内可以ping通的主机ip保存到一个文件
> ip_up.txt
for i in {2..10}
do
{
ip=10.1.1.$i
ping -c1 $ip &>/dev/null
[ $? -eq 0 ] && echo $ip |tee -a ip_up.txt
}& //并行放到后台运行
done
wait //等待进程结束
#将yunwei用户目录下的公钥推送到可以ping的服务器上
#1. 判断yunwei用户下有没有公钥
[ ! -f ~/.ssh/id_rsa.pub ] && ssh-keygen -P "" -f ~/.ssh/id_rsa
#2.将id_rsa.pub公钥远程推送到指定服务器
#2.1 判断expect程序是否安装,没安装则安装它
{
rpm -q expect
[ $? -ne 0 ] && sudo yum -y install expect
for remote_ip in `cat ip_up.txt`
do
/usr/bin/expect <<-EOF
spawn ssh-copy-id root@$remote_ip
expect {
"yes/no" { send "yes\r";exp_continue }
"password:" { send "123\r" }
}
expect eof
EOF
done
} &>/dev/null
#测试验证
test_ip=`tail -1 ip_up.txt`
ssh root@$test_ip hostname
test $? -eq 0 && echo "公钥推送成功。"
写一个脚本,统计web服务的不同连接状态个数
xxxxxxxxxx
#!/bin/bash
#count_http_80_state
#统计每个状态的个数
declare -A state
states=`ss -ant|grep 80|cut -d' ' -f1`
for i in $states
do
let state[$i]++
done
#通过遍历数组里的索引和元素打印出来
for j in ${!state[@]}
do
echo $j:${state[$j]}
done
1、将/etc/passwd里的用户名分类,分为管理员用户,系统用户,普通用户。 2、写一个倒计时脚本,要求显示离2018年6月18日(端午节)的凌晨0点,还有多少天,多少时,多少分,多少秒。 3、写一个脚本把一个目录内的所有空文件都删除,最后输出删除的文件的个数。
xxxxxxxxxx