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-100的奇数,保存到另一个变量里(需要临时变量保存所有的奇数)
- 从1-100中找出奇数后,再相加,然后将和赋值给变量
- 遍历完毕后,将和的值打印出来
案例
- 实现方式一
#!/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-50之间的偶数
- 将获取的偶数保存到
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循环使用
需求
- 使用until语句批量创建10个用户,要求stu1-stu5用户的UID分别是1001–1005;
- stu6-stu10用户的家目录分别在/rhome/stu6–/rhome/stu10;
思路
- 创建用户语句:useradd -u|useradd -d
- 使用循环语句:until批量创建用户
- 判断用户的前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 "网络检查完毕"
嵌套循环
简介
大圈套小圈
- 一个循环体内又包含另外一个完整的循环结构,称为循环嵌套;
- 每次外部循环都会触发内部循环,直到内部循环完成,才接着执行下一次的外部循环;
- for循环、while循环和until循环都可以相互嵌套;
举例
打印指定图案
- 图案一
1
12
123
1234
12345
- 思路一
- 观察图案,可以分为x轴和y轴;
- y轴控制了输出几行,x轴控制了每行输出几个,也就是说y轴为最外层循环,x轴为内层循环;
- 注意:x轴个数与y轴的行数有关系,即当y轴是第1行,那么x轴就打印1个数,依次类推;
- 注意:轴无需换行,而y轴没循环一次还一行;
- 注意: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
- 思路二
- 观察图案,可以分为x轴和y轴;
- y轴控制了输出几行,x轴控制了每行输出几个,也就是说y轴为最外层循环,x轴为内层循环;
- 注意:x轴个数与y轴的行数有关系,即当y轴是第1行,那么x轴就打印1个数,依次类推;
- 注意:轴无需换行,而y轴没循环一次还一行;
- 注意:x轴循环结束后y轴开始下次循环;
- 注意:y轴是正序但x轴是倒序,而且x轴的数字个数与y轴的行数成反比
- 注意:外部循环需要打印换行,且只打印5行,所以循环5次
- 注意:内部循环需要打印数字,且不换行
- 实现二
#####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
- 思路
- 观察图案,可以分为x轴和y轴;
- y轴控制了输出几行,x轴控制了每行输出几个,也就是说y轴为最外层循环,x轴为内层循环;
- 注意:x轴个数与y轴的行数有关系,即当y轴是第1行,那么x轴就打印1个数,依次类推;
- 注意:轴无需换行,而y轴没循环一次还一行;
- 注意:x轴循环结束后y轴开始下次循环;
- 注意: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乘法表
- 思路
- 需要加入算数运算符、制表符
- 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 | 交互,使本地主机与远程主机可以交互 |
执行方式
- “./expect.sh”
- “/路径/expect.sh”
- 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 #代表操作结束
在多台服务器上创建一个用户
- 思路
- 使用循环登录远程主机
- 从自定义的ip_password.txt文件中获取ip、user和password,分别获取变量,从而登录远程主机
- 使用expect解决登录时交互问题
- 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