08. Shell-循环语句

for循环语法结构

列表循环

简介

列表for循环,用于将一组命令执行已知的次数

语法结构

#格式一:
for 变量名字 in {列表}; do
	 commands
   commands
   ...
done

#格式二:
for 变量名字 in 值1 值2 值3; do
	 commands
   commands
   ...
done

举例

  • 格式一举例
#!/bin/env bash

for NUMBER in {1..5}; do
	echo $NUMBER
done
  • 格式二举例
#!/bin/env bash

for NUMBER in 1 2 3 4 5; do
	echo $NUMBER
done
  • 定义步长举例
#!/bin/env bash

for NUMBER in {0..50..2}; do
	echo $NUMBER
done

#{0..50..2}中的2表示步长
  • 序列举例
#普通序列
#!/bin/env bash

for NUMBER in $(seq 10); do
	echo $NUMBER
done

#倒序序列
#!/bin/env bash

for NUMBER in {10..1}; do
	echo $NUMBER
done

#偶数序列
#!/bin/env bash

for NUMBER in {0..10..2}; do
	echo $NUMBER
done

for NUMBER in $(seq 0 2 10); do
	echo $NUMBER
done

#奇数序列
#!/bin/env bash

for NUMBER in {1..10..2}; do
	echo $NUMBER
done

for NUMBER in $(seq 1 2 10); do
	echo $NUMBER
done

不带列表循环

简介

不带列表的for循环,执行时由用户指定参数和参数的个数

语法结构

for 变量名称; do
	 commands
   commands
   ...
done

举例

#!/bin/env bash

for NAME; do
	echo "hello word"
done
chmod a+x test.sh

test.sh a b c

类C风格的for循环

语法结构

#格式一
for (( expr1;expr2;expr3 )); do
	 commands
   commands
   ...
done

expr1:定义变量并赋初值
expr2:决定是否进行循环(条件)
expr3:决定循环变量如何改变,决定循环什么时候退出

举例

#!/bin/env bash

for (( i=1;i<=5;i++ )); do
	echo $i
done

for循环使用

需求

计算1-100的奇数和

思路

  1. 定义一个变量来保存奇数的和(落脚点为计算,计算的结果需要有变量保存)
  2. 找出1-100的奇数,保存到另一个变量里(需要临时变量保存所有的奇数)
  3. 从1-100中找出奇数后,再相加,然后将和赋值给变量
  4. 遍历完毕后,将和的值打印出来

案例

  • 实现方式一

#!/bin/env bash

ODD_SUM=0

for NUMBER in {1..100..2}; do
   ODD_SUM=$(( $ODD_SUM+$NUMBER ))
done
echo $ODD_SUM
  • 实现方式二
#!/bin/env bash

ODD_SUM=0

for NUMBER in {1..100..2}; do
   ODD_SUM=$[ $ODD_SUM+$NUMBER ]
done
echo $ODD_SUM
  • 实现方式三
#!/bin/env bash

ODD_SUM=0

for (( NUMBER=1;NUMBER<=100;NUMBER+=2 )); do
   let ODD_SUM=$ODD_SUM+$NUMBER
done
echo $ODD_SUM
  • 实现方法四
#!/bin/env bash

ODD_SUM=0

for (( NUMBER=1;NUMBER<=100;NUMBER++ )); do
	 if [ $[ $NUMBER%2 ] -ne 0 ]; then
      let ODD_SUM=$ODD_SUM+$NUMBER
   fi
done
echo $ODD_SUM

while循环语法结构

简介

while循环语句,条件为真就进入循环;条件为假就退出循环。

语法结构

#格式一:
while 表达式; do
	 commands
   commands
   ...
done

#注意:
[ 1 -eq 1 ] 等价于 (( 1 = 1 ))
[ 1 -gt 2 ] 等价于 (( 1 > 2 ))

举例

  • while循环
#!/bin/env bash

#使用while循环打印1-5

NUMBER=0
while (( $NUMBER <= 5 )); do
	NUMBER=$(( $NUMBER+1 ))
  echo $NUMBER
done
  • for循环
#!/bin/env bash

#使用for循环打印1-5

for NUMBER in {1..5}; do
	echo $NUMBER
done

while循环使用

思路

  1. 设置一个变量用于存放偶数的和
  2. 如何获取1-50之间的偶数
  3. 将获取的偶数保存到

for循环案例

#!/bin/env bash

#计算1-50的偶数和

EVEN_SUM=0
for (( i=0;i<=50;i+=2)); do
	let EVEN_SUM=$(( $EVEN_SUM + $i ))
done
echo $EVEN_SUM

while循环案例

#!/bin/env bash

#计算1-50的偶数和

EVEN_SUM=0
i=2
while [ $i -le 50 ]; do
	 let EVEN_SUM=$(( $EVEN_SUM + $i ))
   let i+=2
done
echo $EVEN_SUM

until循环语法结构

简介

until循环,条件为假就进入循环;条件为真就退出循环。

语法结构

until 条件表达式; do
	 commands
   commands
   ...
done

#注意:
[ 1 -eq 1 ] 等价于 (( 1 = 1 ))
[ 1 -gt 2 ] 等价于 (( 1 > 2 ))

举例

  • while循环
#!/bin/env bash

i=1
while (( $i <= 5 )); do
	 echo $i
   let i++
done
  • until循环-倒序
#!/bin/env bash

i=5
until (( $i < 1 )); do
	 echo $i
   let i--
done
  • until循环-正序
#!/bin/env bash

i=1
until (( $i > 5 )); do
	 echo $i
   let i++
done

until循环使用

需求

  1. 使用until语句批量创建10个用户,要求stu1-stu5用户的UID分别是1001–1005;
  2. stu6-stu10用户的家目录分别在/rhome/stu6–/rhome/stu10;

思路

  1. 创建用户语句:useradd -u|useradd -d
  2. 使用循环语句:until批量创建用户
  3. 判断用户的前5个和后5个

until循环案例

  • 案例一
#!/bin/env bash

if [ -d /rhome ]; then
	echo "/rhome目录已存在"
else
	mkdir /rhome
  echo "/rhome不存在,已完成创建"
fi

i=1
until (( $i <= 5 )); do
	 useradd stu$i -u $[ 1000 + $i ]
   let i++
done

until (( $i <= 10 )); do
	 useradd stu$i -d /rhome/stu$i
   let i++
done
  • 案例二
#!/bin/env bash

if [ -d /rhome ]; then
	echo "/rhome目录已存在"
else
	mkdir /rhome
  echo "/rhome不存在,已完成创建"
fi

i=1
until (( $i <= 5 )); do
	 if [ $i -le 5 ]; then
      useradd -u $[ 1000 + $i ] stu$i
      echo "123456" | passwd --stdin stu$i
   else
      useradd -d /rhome/stu$i
      echo "123456" | passwd --stdin stu$i
   fi
   let i++
done

并发控制

简介

并发控制指控制程序多并发执行。
“{程序代码}&”表示将程序放到后天并行执行。如果需要等待程序执行完毕后再执行后续代码,需要添加“wait”。

  • 注意:

针对哪块代码并行处理就用“{}&”括起来那段代码。

语法结构

{
	commands
  commands
  ...
}&

wait

举例

#!/bin/env bash

#判断主机网络通信情况

IP_ADDRESS=192.169.1

for IP_NUBMER in {200..210}; do
{
  ping -c 1 $IP_ADDRESS.$IP_NUBMER &> /dev/null 
  [ $? -eq 0 ] && echo $IP_ADDRESS.$IP_NUBMER is OK >> /root/IP_OK.txt || echo $IP_ADDRESS.$IP_NUBMER is DOWN >> /root/IP_NO.txt
}&
done

wait

echo "网络检查完毕"

嵌套循环

简介

大圈套小圈

  1. 一个循环体内又包含另外一个完整的循环结构,称为循环嵌套;
  2. 每次外部循环都会触发内部循环,直到内部循环完成,才接着执行下一次的外部循环;
  3. for循环、while循环和until循环都可以相互嵌套;

举例

打印指定图案

  • 图案一
1
12
123
1234
12345
  • 思路一
  1. 观察图案,可以分为x轴和y轴;
  2. y轴控制了输出几行,x轴控制了每行输出几个,也就是说y轴为最外层循环,x轴为内层循环;
  3. 注意:x轴个数与y轴的行数有关系,即当y轴是第1行,那么x轴就打印1个数,依次类推;
  4. 注意:轴无需换行,而y轴没循环一次还一行;
  5. 注意:x轴循环结束后y轴开始下次循环;
  • 实现一
#####for+for循环
#!/bin/env bash

#打印图形

for y in {1..5}; do
	 for (( x=1;x<=y;x++ )); do
      echo -n $x
   done
   echo
done

#####for+while循环
#!/bin/env bash

#打印图形

for (( y=1;y<=5;y++ )); do
	 x=1
	 while (( $x<=$y )); do
      echo -n $x
      let x++
   done
   echo
done
  • 图案二
5
54
543
5432
54321
  • 思路二
  1. 观察图案,可以分为x轴和y轴;
  2. y轴控制了输出几行,x轴控制了每行输出几个,也就是说y轴为最外层循环,x轴为内层循环;
  3. 注意:x轴个数与y轴的行数有关系,即当y轴是第1行,那么x轴就打印1个数,依次类推;
  4. 注意:轴无需换行,而y轴没循环一次还一行;
  5. 注意:x轴循环结束后y轴开始下次循环;
  6. 注意:y轴是正序但x轴是倒序,而且x轴的数字个数与y轴的行数成反比
  7. 注意:外部循环需要打印换行,且只打印5行,所以循环5次
  8. 注意:内部循环需要打印数字,且不换行
  • 实现二
#####while+for循环
#!/bin/env bash

#打印图形

y=1
while (( $y<=5 )); do
	for (( x=5;x>=6-$y;x-- )); do
  	echo -n $x
  done
echo
let y++
done

#####for+for循环
#!/bin/env bash

#打印图形

for (( y=5;y>=1;y-- )); do
	 for (( x=5;x>=$y;x-- )); do
    	echo -n $x
   done
echo
done
  • 图案三
54321
5432
543
54
5
  • 思路
  1. 观察图案,可以分为x轴和y轴;
  2. y轴控制了输出几行,x轴控制了每行输出几个,也就是说y轴为最外层循环,x轴为内层循环;
  3. 注意:x轴个数与y轴的行数有关系,即当y轴是第1行,那么x轴就打印1个数,依次类推;
  4. 注意:轴无需换行,而y轴没循环一次还一行;
  5. 注意:x轴循环结束后y轴开始下次循环;
  6. 注意:y轴是正序但x轴是倒序
  • 实现
#!/bin/env bash

#打印图形

for y in {1..5}; do
	 for (( x=5;x>=y;x-- )); do
  	 echo -n "$x"
   done
   echo
done

打印99乘法表

  • 思路
  1. 需要加入算数运算符、制表符
  2. y控制输出行数,x控制输出列数,z用于x和y的运算结果
  • 案例
#!/bin/env bash

#打印99乘法表

for y in {1..9}; do
	 for (( x=1;$x<=$y;x++ )); do
      echo -n -e "$x x $y = $(( $y * $x ))\t"
   done
   echo
done

影响shell程序的内置命令

常用命令

命令解释
exit退出整个程序
break结束当前循环,或跳出本层循环
continue忽略本次循环剩余的代码,直接进入下一次循环
shift使位置参数向左移动,默认移动1位,可以使用shift 2,使位置移动2位

exit应用举例

#!/bin/env bash

for x in {1..5}; do
	 if [ $x -ne 3 ]; then
      echo $x
    	exit
   fi
done

break应用举例

#!/bin/env bash

for x in {1..5}; do
	 if [ $x -eq 3 ]; then
      echo $x
    	break
   fi
done

continue应用举例

#!/bin/env bash

for x in {1..5}; do
	 if [ $x -ne 3 ]; then
      echo $x
    	continue
   fi
done

shift应用举例

  • 需求

让脚本能给实现用户自定义输入数字,然后脚本计算和

  • for案例
#!/bin/env bash

#计算自定义输入数字

insert_sum=0

for insert_num; do
	 let insert_sum=$insert_sum+$insert_num
done
echo $insert_sum
  • while案例
#!/bin/env bash

#计算和

insert_sum=0

while [ $# -ne 0 ]; do
	 let insert_sum=$insert_sum+$1
   shift
done
echo $insert_sum

expect的扩展

简介

expect是一款自动应答的工具,使用的是tcl语言。

安装

#检查有没有安装expect

#安装expect
yum -y install expect

用法

基本参数

参数功能
spawn开启一个程序,后跟上动作
expect定义期望的结果,可以定义多个
exp_continue如抓不到关键字,继续执行后续内容,注意“;”是必须项
interact交互,使本地主机与远程主机可以交互

执行方式

  1. “./expect.sh”
  2. “/路径/expect.sh”
  3. expect -f /路径/expect.sh

基础语法

  • 定义变量
    • 在expect中定义变量使用set命令
    • 格式:set 变量名 变量值
    • 举例:set ip 192.168.1.23
  • 调用变量
    • $变量名
  • 定义位置参数
    • 使expect也可以获取脚本参数,0表示第一个参数,1表示第二个依次类推
    • 格式:set 变量名 [ lindex $argv 位置 ]
    • 举例:set user [ lindex $argv 0 ]

举例

主机免密远程登录

#!/usr/bin/env expect

#开启一个程序
spawn ssh root@192.168.43.212

#捕获相关信息
expect {
	 "(yes/no)?" { send "yes\r";exp_continue }
   "password:" { send "123456\r" }
}
interact

主机免密远程登录-带有变量

#!/usr/bin/env expect

#定义变量
set ip 192.168.43.212
set user root
set password cmk521

#开启一个程序
spawn ssh $user@$ip

#捕获相关信息
expect {
	 "(yes/no)?" { send "yes\r";exp_continue }
   "password:" { send "$password\r" }
}
interact

主机免密远程登录并执行命令

#!/usr/bin/env expect

#定义变量
set ip 192.168.43.212
set user root
set password cmk521

#开启一个程序
spawn ssh $user@$ip

#捕获相关信息
expect {
	 "(yes/no)?" { send "yes\r";exp_continue }
   "password:" { send "$password\r" }
}

#操作发送至远程
expect "#"
send "rm -rf /tmp/*\r"
send "touch /tmp/file{1..3}.txt\r"
send "hostname\r"
send "date\r"
send "exit\r"
expect eof			#代表操作结束

在多台服务器上创建一个用户

  • 思路
  1. 使用循环登录远程主机
  2. 从自定义的ip_password.txt文件中获取ip、user和password,分别获取变量,从而登录远程主机
  3. 使用expect解决登录时交互问题
  4. bash使用expect
  • 举例
#创建ip、user和password文件
cat >> /root/ip_password.txt << EOF
192.168.43.211 root cmk521
192.168.43.212 root cmk521
192.168.43.213 root cmk521
EOF

#编辑配置文件
#!/bin/env bash

while read ip user password; do
	 /usr/bin/expect <<-END &>/dev/null
   spawn ssh $user@$ip
   expect {
      "yes/no" { send "yes\r";exp_continue }
      "password:" { send "$password\r" }
   }
   expect "#" { send "useradd test; rm -rf /tmp/*; exit\r" }
   expect eof
   END
echo "$ip 服务器用户创建完毕"
done < /root/ip_password.txt
  • 11
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值