for循环是编程语言中一种循环语句
for循环语法
#写法1 for 变量 in 取值列表 do 代码块 done #写法2 for ((i==1;i<=100;i++)) do 代码块 done
while,until循环语法
while [表达式] do 条件满足执行的代码块 变量的迭代方式 done until [表达式] #与while区别在于,while满足条件执行,until满足条件终止 do 条件不成立执行的代码块 变量的迭代方式 done
示例1:循环读取user.txt中的用户名,创建用户。设置密码。
for i in $(cat /opt/user.txt) do useradd $i echo 123456 | passwd --stdin $i done
示例2:循环读取ipaddr文本文件中地址,执行ping命令,获取结果。根据执行结果将存货的主机地址和不存活的主机地址区分写入两个文件
[root@xue opt]# cat pingtofile.sh for i in $(cat /opt/ipaddr.txt) do ping -c 3 -W 2 $i &> /dev/null #-c 3 ping3次 -W 2 等待时间2s &> /dev/null报错信息导入空设备不显示 if [ $? == 0 ] then echo $i >> /opt/ipservive.txt else echo $i >> /opt/ipdie.txt fi done
示例3 从1累加到100
sum=0 for i in {1..100} do sum=$(($i+$sum)) done echo $sum
常用转义字符
echo -n 表示不换行输出
echo -e 输出转义字符,将转义后的内容输出到屏幕上echo -ne
只有加了-e才能执行下面的转义符:
\b 转义后相当于按退格键(backspace),但前提是"\b"后面存在字符;"\b"表示删除前一个字符,"\b\b"表示删除前两个字符。\c 不换行输出,在"\c"后面不存在字符的情况下,作用相当于 echo -n; 但是当"\c"后面仍然存在字符时,"\c"后面的字符将不会被输出。
\n 换行,被输出的字符从"\n"处开始另起一行。
\f 换行,但是换行后的新行的开头位置连接着上一行的行尾;\v 与\f相同;
\t 转以后表示插入tab,即横向制表符;
\r 光标移至行首,但不换行,相当于使用"\r"以后的字符覆盖"\r"之前同等长度的字符;但是当"\r"后面不存在任何字符时,"\r"前面的字符不会被覆盖
\\ 表示插入"\"本身;
使用转义字符-n实现不换行效果
echo "-n不换行" for i in {1..9} do echo -n "*" done echo echo "普通输出换行" for i in {1..9} do echo "*" done
使用嵌套for循环搭配转义字符-n输出正三角
for i in {1..9} #外循环,实现行输出 do for ((j=1;j<=i;j++)) #内循环,实现列输出 do echo -n "*" #每列不换行输出*,输出多少个*取决于上面的j循环(输出个数与行数相关) done echo #此echo为外循环每行换行使用 done
改进正三角,结合-ne 输出九九乘法表
for i in {1..9} #外循环,实现行输出 do for ((j=1;j<=i;j++)) #内循环,实现列输出 do echo -ne "$i*$j=$(($i*$j))\t" #-ne:n不换行输出,-e:为了使用转义符\t。\t:制表符 由于分隔输出 done echo #此echo为外循环每行换行使用 done
跳出for循环:continue与break
continue跳出循环,循环内部跳过本次循环并继续下一次循环
break打破循环,直接跳出循环不再执行
continue 2表示跳出2层循环
continue 3表示跳出3层循环
continue 4表示跳出4层循环
continue 5表示跳出5层循环
不写数字默认为1,continue 1跳出当前循环
break写法同理。
[root@xue opt]# cat continue.sh #直接跳过1层当前循环 echo "continue" for a in {1..5} do for b in {1..5} do if [ $b -eq 3 ] then continue fi echo -ne "a=$a-b=$b\t\t" done echo done echo echo echo #直接跳过2层循环 echo "continue 2" for a in {1..5} do for b in {1..5} do if [ $b -eq 3 ] then continue 2 fi echo -ne "a=$a-b=$b\t\t" done echo done echo echo echo #直接破除1层当前循环 echo "break" for a in {1..5} do for b in {1..5} do if [ $b -eq 3 ] then break fi echo -ne "a=$a-b=$b\t\t" done echo done echo echo echo #直接破除2层循环 echo "break 2" for a in {1..5} do for b in {1..5} do if [ $b -eq 3 ] then break 2 fi echo -ne "a=$a-b=$b\t\t" done echo done
exit 退出当前脚本执行,自定义返回状态码
由于脚本执行后使用预定义变量#?查看执行结果只能显示上一条命令执行是否发生了问题(例如此处的netstat)即使没有httpd服务也会正常执行返回0,此时可以使用exit 2,自定义返回2。
执行该脚本后在用#?查看,返回值为2。
(此处的事例仅仅作为一个演示,没有实际用途)
进阶例题
while 循环创建用户
i=1 while [ $i -le 10 ] do useradd user${i} echo "123456" | passwd --stdin user${i} &> /dev/null let i++ done
while 猜测价格
[root@xue opt]# cat caijia.sh price=$[RANDOM%100+1] #0-32767 i=0 while true do read -p "input the price" exp let i++ if [[ $exp -gt $price ]] then echo '高了!' elif [[ $exp -lt $price ]] then echo '低了!' else echo '猜对了' break fi done echo "你猜了$i 次"
for 网段持续检测
read -p "请输入一个网段(such like 192.168.80)" wangduan for zhuji in {1..254} do ping -c 3 -W 2 ${wangduan}.${zhuji} &> /dev/null if [ $? -eq 0 ] then echo "${wangduan}.${zhuji} is online!!!" echo ${wangduan}.${zhuji} >> /opt/serviceip.txt else echo "${wangduan}.${zhuji} is offline" fi done
完善代码,添加 { }& 并发。
由于ping需要时间,一个个ping耗时太长,使用 { }& 包裹ping语句,使其并发执行
read -p "请输入一个网段(such like 192.168.80)" wangduan for zhuji in {1..254} do { #✨ ping -c 3 -W 2 ${wangduan}.${zhuji} &> /dev/null if [ $? -eq 0 ] then echo "${wangduan}.${zhuji} is online!!!" echo ${wangduan}.${zhuji} >> /opt/serviceip.txt else echo "${wangduan}.${zhuji} is offline" fi }& #✨ done wait #✨若有的线程较快,会直接执行下面的cat导致显示不全,加上wait,使得所有线程执行完后才执行下面的命令 cat /opt/serviceip.txt
for 多文件合并到一个文件
for sb in /opt/*.sh #for循环查找文件 do cat "$sb" >> hebing.txt #内容重定向到文本文件 done
for 显示文件夹所有文件 (在生产环境中不允许使用ll,ls命令。可以通过shell脚本获取)
for sb in * do echo "$sb" done
改进,排除文件夹
for sb in * do test -f $sb #是否为文件 (排除目录) if [ $? -wq 0 ] then echo "$sb" fi done ~
while shell计算器
while true == for ((;;)) #都可以死循环
while true do read -p '输入数字1 ' num1 read -p '选择加减乘除+—x/ ' jjcc read -p '输入数字2 ' num2 if [ $jjcc == '+' ] then echo $(($num1+$num2)) fi if [ $jjcc == '-' ] then echo $(($num1-$num2)) fi if [ $jjcc == 'x' ] then echo $(($num1*$num2)) fi if [ $jjcc == '/' ] then echo $(($num1/$num2)) fi echo done
优化版代码
使用[[ ]]
变量全部加上" "
符合语言规范
while true do read -p "请输入第一个整数:" num1 read -p "请输入运算符:加(+);减(-);乘(*);除(/);求余(%):" fh read -p "请输入第二个整数:" num2 if [[ "$fh" == "+" ]] then echo "结果为:$(($num1 + $num2))" elif [[ "$fh" == "-" ]] then echo "结果为:$(($num1 - $num2))" elif [[ "$fh" == "*" ]] then echo "结果为:$(($num1 * $num2))" elif [[ "$fh" == "/" ]] then echo "结果为:$(($num1 / $num2))" elif [[ "$fh" == "%" ]] then echo "结果为:$(($num1 % $num2))" else echo "输入有误!" fi done
while 商店选购
选择是否进入商店。进入商店则选购产品。不进入商店则结算。显示花费了多少资金。
[root@xue opt]# cat shop.sh sum=0 count=0 while true do read -p "是否进入商店?y/n " enter if [ $enter == "y" ] then let count++ read -p "输入商品数字 1.衣服500 2.裤子400 3.鞋子350 4.帽子150 5.袜子50 " sp case $sp in 1) let sum+=500 ;; 2) let sum+=400 ;; 3) let sum+=350 ;; 4) let sum+=150 ;; 5) let sum+=50 ;; *) break esac else break fi done echo "共进入商店$count 次 ,共消费$sum 元"
小技巧 seq命令
seq 1 2 10 #从1开始,每隔2,输出直到10 seq 2 3 10 #从2开始,每隔3,输出直到10