1.for循环
1.1语法
方法一:
for 变量 in 取值列表
do
命令列表
done
for 变量 in 取值列表;do
命令列表
done
方法二:
for NAME [in WORDS ... ] ; do COMMANDS; done
方法三:
for ((初始值;循环变化条件;变量变化)) ##类C风格
do
命令列表
done
1.2实例
1>批量创建多用户
#!/bin/bash
for name in `cat /mnt/a.txt` #提前创建好a.txt,用户名每行一个
do
id $name &> /dev/null
if [ $? -ne 0 ];then
useradd $name
echo "123456" | passwd --stdin $name &> /dev/null
else
echo "user $name is exist "
fi
done
2>批量创建用户,将用户加入到hopu组中
#!/bin/bash
grep -w ^hopu /etc/group &>/dev/null
if [ $? -ne 0 ];then
groupadd hopu
fi
for ((i=1;i<=5;i++))
do
useradd -G hopu user$i
echo 123456 |passwd --stdin user$i
done
3>计算1到100的总数值
方法1)
echo {1..100}|tr ' ' +|bc
方法2)
#!/bin/bash
sum=0
for i in {1..100}
do
let sum+=i
done
echo "sum=$sum"
==========
方法3:C风格脚本
#!/bin/bash
for ((sum=0,i=1;i<=100;i++));do
let sum+=i
done
echo $sum
4>使用for循环来检查192.168.10.0网段IP地址是否联通
#!/bin/bash
ip=192.168.10
for ((i=1;i<=255;i++))
do
ping -c1 -i 0.2 $ip.$i &>/dev/null
if [ $? -eq 0 ];then
echo "$ip.$i is up" >>/tmp/ip_up.txt
else
echo "$ip.$i is down" >>/tmp/ip_down.txt
fi
done
#shell脚本并发控制测试
{程序}&表示将程序放到后台执行,如果需要等待程序执行完在进行下面的内容,就在done的后面加wait
#!/bin/bash
ip=192.168.10
for ((i=1;i<=254;i++))
do
{
ping -c1 -i 0.2 $ip.$i &>/dev/null
if [ $? -eq 0 ];then
echo "$ip.$i is up" >>/tmp/ip_up.txt
else
echo "$ip.$i is down" >>/tmp/ip_down.txt
fi
}&
done
wait
echo "ip 地址检查完毕!"
5>计算1-100之间的奇数的值
方法1:
#!/bin/bash
sum=0
for i in {1..100..2}
do
let sum=sum+$i
done
echo sum=$sum
方法2:
#类c风格写法:
#!/bin/bash
sum=0
for ((i=1;i<=100;i+=2))
do
let sum=sum+$i
done
echo sum=$sum
6>打印九九乘法表
语法1:
#!/bin/bash
set -ue
for i in {1..9}
do
for j in `seq $i`
do
echo -en "${i}x${j}=$((i*j))\t"
done
echo ""
done
======
语法2:C风格的
#!/bin/bash
for ((i=1;i<=9;i++));do
for((j=1;j<=i;j++));do
echo -en "${j}x$i=$((j*i))\t"
done
echo
done
2.while循环
2.1语法
语法格式一:
while [条件]
do
操作
done
语法格式二:
while read line
do
操作
done < file
通过read命令每次读取一行文件,文件内容有多少行,while循环多少次
2.2实例
1>打印1-5
#!/bin/bash
i=1
while [ $i -le 5 ]
do
echo $i
let i++
done
2>计算10以内平方数
#!/bin/bash
num=1
while [ $num -lt 10 ]
do
sum=$(expr $num \* $num)
echo "$num * $num = $sum"
#let num++
((num++))
done
=========
#!/bin/bash
num=1
while [ $num -lt 10 ]
do
sum=$((num*num))
echo "$num * $num = $sum"
#let num++
((num++))
done
2.3无限循环模式
2.3.1 语法
方法一:
while :
do
命令
done
方法二:
for (( ; ; ))
方法三:
while true
do
命令
done
2.3.2实例
1>猜价格
#!/bin/bash
price=50
times=0
echo "商品的实际价格为0-99之间,猜猜看是多少? "
while true
do
read -p "input a price: " int
let times++
if [ $int -eq $price ];then
echo "恭喜,猜对了"
echo "你一共猜了 $times 次"
exit 105
elif [ $int -gt $price ];then
echo "猜大了"
else
echo "猜小了"
fi
done
2>查看系统信息
#!/bin/bash
echo "请根据下面的提示选择查看对应的功能"
while :
do
cat <<EOF
h 显示查看帮助信息
f 显示查看内存使用信息
d 显示查看磁盘使用信息
p 显示查看系统负载信息
q 退出!
EOF
read -p "请根据上面的序号选择对应的功能:" sys
case $sys in
h|H)
cat <<EOF
h 显示查看帮助信息
f 显示查看内存使用信息
d 显示查看磁盘使用信息
p 显示查看系统负载信息
q 退出!
EOF
;;
f|F)
free -h
;;
d|D)
df -h
;;
p|P)
uptime
;;
q|Q)
exit
;;
esac
done
3until循环
3.1语法
和while刚好相反,只要不满足条件就一直循环
until expression
do
command
done
3.2实例
1>打印1到100的值
#!/bin/bash
# 定义变量的初始值
i=1
sum=0
# until循环
until (($i > 100))
do
let sum=$sum+$i
let i++
done
echo "1-100之间的和:$sum"
2>使用until批量创建10个用户,要求用户是从stu1-stu10,要求设置用户的家目录在/mnt/stu
#!/bin/bash
i=1
if [ -d /mnt/user ];then
echo "/mnt/stu目录已经存在"
else
mkdir /mnt/user
fi
until [ $i -gt 10 ]
do
if [ $i -le 10 ];then
useradd -d /mnt/user/stu$i stu$i && echo "123456"|passwd --stdin stu$i
else
echo "user is exist"
fi
let i++
done
4. 循环语句嵌套
4.1概念
**关键字:大圈套小圈**
1. 一个循环体内又包含另一个**完整**的循环结构,称为循环的嵌套。
2. 每次外部循环都会触发内部循环,直至内部循环完成,才接着执行下一次的外部循环。
3. for循环、while循环和until循环可以**相互**嵌套。
4.2语法
方法一:
for 变量1 in
do
for 变量2 in
do
命令2
done
命令1
done
方法二:
for 变量1 in
do
if […];then
fi
命令1
done
4.3实例
1>添加用户脚本
#!/bin/bash
#add user
while :
do
read -p "please enter prefix & password & num: " prefix pass num
printf "user information:
-------------------------
user prefix: $prefix
user passwd: $pass
user number: $num
-------------------------
"
for i in `seq -w $num`
do
user=${prefix}${i}
id $user &> /dev/null
if [ $? -ne 0 ];then
useradd $user && echo "$pass" | passwd --stdin $user &> /dev/null
if [ $? -eq 0 ];then
echo -e "\e[31m$user\e[0m created"
fi
else
echo "user $user exist"
fi
done
exit 100
done
2>写一个收集服务器的内存的脚本,当内存使用率大于80%时发送告警
#!/bin/bash
date=`date +"%F %T"`
percentage=30
while true;
do
mem_usage=`free -m | sed -n '2p'|awk '{ print ($3+$6)/$2*100 }'`
if [ `expr "$mem_usage > $percentage"` ]; then
echo "memory's warning $date memory:$mem_usage%" |mail -s "warning" wuchaofengainio@163.com
else
echo "memory is normal"
echo "$mem_usage%"
fi
sleep 30
done
3>打印指定的图形
5
54
543
5432
54321
方法1:
#!/bin/bash
y=5
while (( $y >= 1 ));do
for ((x=5;x>=$y;x--));do
echo -n $x
done
echo
let y--
done
方法2:
#!/bin/bash
for (( y=5;y>=1;y--))
do
for (( x=5;x>=$y;x--))
do
echo -n $x
done
echo
done
# 直角三角形
*
**
***
****
*****
#!/bin/bash
for ((i=1;i<=5;i++));do
for((j=1;j<=i;j++));do
echo -e "*\c"
done
echo
done
# 等腰三角形
*
***
*****
*******
*********
#!/bin/bash
for ((i=1;i<=10;i++));do
for ((k=1;k<=10-i;k++));do
echo -e " \c"
done
for((j=1;j<=2*i-1;j++));do
echo -e "*\c"
done
echo
done
4>使用while循环来判断http服务是否正常,如果异常则启动服务,并记录服务启动时间,反之就打印服务正常。
#!/bin/bash
# 定义HTTP服务的URL
url="http://192.168.1.100"
# 定义最大尝试次数
max_attempts=5
# 定义当前尝试次数
current_attempt=0
# 定义服务启动日志文件路径
log_file="/mnt/log/file.log"
# 判断HTTP服务是否正常
while [ $current_attempt -lt $max_attempts ]; do
# 发送HTTP请求
response=$(curl -s -o /dev/null -w "%{http_code}" $url)
# 检查HTTP响应状态码
if [ $response -eq 200 ]; then
echo "HTTP service is up and running." >> $log_file
break
else
echo "HTTP service is down. Attempt $current_attempt." >> $log_file
# 在这里添加启动HTTP服务的命令,例如:
systemctl start httpd &>> $log_file
if [ $? -eq 0 ];then
echo "http服务启动成功"
else
echo "http服务启动失败"
fi
current_attempt=$((current_attempt + 1))
fi
done
5.exit语句
5.1概念
exit 是一个Shell内置命令,用来退出当前 Shell 进程,并返回一个退出状态;使用$?可以接收这个退出状态。0表示成功,其他数字表示失败
5.2语法
exit [返回值]
5.3案例
1>判断输入的是否是数字
#!/bin/bash
read -t 30 -p "please input num: " num
y=$( echo $num | sed 's/[0-9]//g' )
if [ -n "$y" ]
then
echo "please input number,error!!!!"
exit 120
else
echo $num
fi
输出
[root@ali01 ~]# ./exit.sh
please input num: ws
please input number,error!!!!
[root@ali01 ~]# echo $?
120
[root@ali01 ~]#
注意:exit是退出当前进程,在脚本中的应用就是退出当前脚本进程,也就是执行到exit后,直接退出,不再执行后续命令,所以说,exit需要谨慎写入,确保执行完你想要的效果后再退出。
2>判断输入是否是yes/no
#!/bin/bash
read -p "请输入(yes|no):" al
case $al in
"yes")
echo "您输入的是yes"
exit 1 #当选择的是yes后,程序就退出了,不在打印“您的选择是yes”这句话。
echo "您的选择是yes"
;;
"no")
echo "您输入的是no"
echo "您的选择是no哦"
;;
*)
echo "输入错误,请输入yes|no"
esac
6.提前结束循环语句
6.1break
6.1.1语法
break n
n 表示跳出循环的层数,如果省略 n,则表示跳出当前的整个循环。break 关键字通常和 if 语句一起使用,即满足条件时便跳出循环。
6.1.2案例
1>判断输入的数字是否大于0,如果小于等于0则循环终止
#!/bin/bash
echo "请输入大于0的数字"
sum=0
while read num; do
if ((num>0)); then
((sum+=num))
else
break
fi
done
echo "sum=$sum"
6.1.3使用 break 跳出双层循环
#!/bin/bash
for((i=1; i<=10; i++)); do
for((j=1; j<=10; j++)); do
if ((i*j==12)); then
break
fi
printf "%d*%d=%-4d" $i $j $((i*j)) #%s %c %d %f都是格式替代符,-表示将左对齐,不加-表示右对齐
done
printf "\n"
done
输出
[root@localhost shells]# bash break.sh
1*1=1 1*2=2 1*3=3 1*4=4 1*5=5 1*6=6 1*7=7 1*8=8 1*9=9 1*10=10
2*1=2 2*2=4 2*3=6 2*4=8 2*5=10
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 5*6=30 5*7=35 5*8=40 5*9=45 5*10=50
6*1=6
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 7*8=56 7*9=63 7*10=70
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 8*9=72 8*10=80
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81 9*10=90
10*1=10 10*2=20 10*3=30 10*4=40 10*5=50 10*6=60 10*7=70 10*8=80 10*9=90 10*10=100
6.2 continue
6.2.1语法
continue n
- 如果省略 n,则表示 continue 只对当前层次的循环语句有效,遇到 continue 会跳过本次循环,忽略本次循环的剩余代码,直接进入下一次循环。
- 如果带上 n,比如 n 的值为 2,那么 continue 对内层和外层循环语句都有效,不但内层会跳过本次循环,外层也会跳过本次循环,其效果相当于内层循环和外层循环**同时**执行了不带 n 的 continue
6.2.2案例
1>打印1-10的数字
#!/bin/bash
for (( i=1;i<=10;i=i+1 ))
do
if [ "$i" -eq 4 ]
then
continue
fi
echo $i
done
6.2.3使用 continue 跳出双层循环
#!/bin/bash
for((i=1; i<=10; i++)); do
for((j=1; j<=10; j++)); do
if ((i*j==12)); then
continue
fi
printf "%d*%d=%-4d" $i $j $((i*j))
done
printf "\n"
done
输出
[root@localhost shells]# bash continue2.sh
1*1=1 1*2=2 1*3=3 1*4=4 1*5=5 1*6=6 1*7=7 1*8=8 1*9=9 1*10=10
2*1=2 2*2=4 2*3=6 2*4=8 2*5=10 2*7=14 2*8=16 2*9=18 2*10=20
3*1=3 3*2=6 3*3=9 3*5=15 3*6=18 3*7=21 3*8=24 3*9=27 3*10=30
4*1=4 4*2=8 4*4=16 4*5=20 4*6=24 4*7=28 4*8=32 4*9=36 4*10=40
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 5*6=30 5*7=35 5*8=40 5*9=45 5*10=50
6*1=6 6*3=18 6*4=24 6*5=30 6*6=36 6*7=42 6*8=48 6*9=54 6*10=60
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 7*8=56 7*9=63 7*10=70
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 8*9=72 8*10=80
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81 9*10=90
10*1=10 10*2=20 10*3=30 10*4=40 10*5=50 10*6=60 10*7=70 10*8=80 10*9=90 10*10=100
6.3break 和 continue 的区别
break 用来结束所有循环,循环语句不再有执行的机会;continue 用来结束本次循环,直接跳到下一次循环,如果循环条件成立,还会继续循环
7 位移 shift
shift命令用于对参数的移动(左移),通常用于在不知道传入参数个数的情况下依次遍历每个参数然后进行相应处理
7.1 shift语法
shift [num]
7.2 实例
1>打印参数个数
#!/bin/bash
while [ "$1" ];do
echo "第一个参数为:$1,参数个数为:$#"
shift
done
输出
[root@localhost shells]# bash shift.sh a b c d
第一个参数为:a,参数个数为:4
第一个参数为:b,参数个数为:3
第一个参数为:c,参数个数为:2
第一个参数为:d,参数个数为:1
从上可知 shift(shift 1) 命令每执行一次,变量的个数($#)减一 (之前的$1变量被销毁,之后的$2就变成了$1),而变量值提前一位。
2>创建用户
#!/bin/bash
#********************************************************************
#Author: wcfeng
#QQ: 452495750
#Date: 2022-01-09
#FileName: shift_adduser.sh
#Description: The test script
#********************************************************************
while [ $1 ];do
if id $1 &>/dev/null;then
echo $1 is exist!
else
useradd $1
fi
shift
done
echo "All user is created"
输出
[root@localhost shells]# bash shift_adduser.sh user1 user2 user3
All user is created
[root@localhost shells]# tail -3 /etc/passwd
user1:x:1003:1003::/home/user1:/bin/bash
user2:x:1004:1004::/home/user2:/bin/bash
user3:x:1005:1005::/home/user3:/bin/bash
3>使用shifts实现计算器效果
#!/bin/bash
sum=0
while [ $# -ne 0 ] #判断参数的个数是否为0,如果不为0则开始计算
do
let sum=$sum+$1
shift
done
echo $sum
输出
[root@localhost shell]# bash shift2.sh 1 2 3
6
8 函数
8.1 概念
将一段代码组合封装在一起实现某个特定的功能或返回某个特定的值,然后给这段代码取个名字,也就是函数名,在需要实现某个特定功能的时候直接调用函数名即可。
简单的说,函数的作用就是把程序多次调用相同的代码部分定义成一份,然后为这一份代码定义一个名字,其它所有重复调用这部分代码就都只调用定义的这个名字就可以了,当需要修改这部分重复代码时,只需要修改函数体内的一部分代码即可实现所有调用修改。
8.2优势
①把相同的程序定义成函数,可以减少整个程序的代码量
②增加程序的可读性、异读性,以及可管理性。
③可以实现程序功能模块化,不同的程序使用函数模块化。
函数名的定义和定义变量的规则基本一致,但是函数名允许以数字开头。
8.3语法
function name() {
statements
[return value]
}
对各个部分的说明:
function
是 Shell 中的关键字,专门用来定义函数;name
是函数名;statements
是函数要执行的代码,也就是一组语句;return value
表示函数的返回值,其中 return 是 Shell 关键字,专门用在函数中返回一个值;这一部分可以写也可以不写。
由{ }
包围的部分称为函数体,调用一个函数,实际上就是执行函数体中的代码。
8.4定义的简化写法
如果你嫌麻烦,函数定义时也可以不写 function 关键字:
name() {
statements
[return value]
}
如果写了 function 关键字,也可以省略函数名后面的小括号:
function name() {
statements
[return value]
}
8.5调用脚本
8.5.1 脚本中调用
[root@localhost shell]# cat fun2.sh
#!/bin/bash
hello(){
echo "您好,欢迎下次光临!"
}
[root@localhost shell]# cat fun3.sh
#!/bin/bash
menu() {
cat <<-EOF
欢迎选购,今日水果清单如下:
1.苹果
2.香蕉
3.菠萝
4.橘子
5.猕猴桃
EOF
}
menu
source /root/shell/fun2.sh
read -p "请输入你要选择的水果编号:" num
case $num in
1)
echo 您选择的是苹果;;
2)
echo 您选择的是香蕉;;
3)
echo 您选择的是菠萝;;
4)
echo 您选择的是橘子;;
5)
echo 您选择的是猕猴桃;;
*)
echo 请选择1-5之间的数字;;
esac
hello
8.6 函数返回值
8.6.1 return 返回值 – 即函数的执行状态
Shell 中的 return 返回值表示的是函数的退出状态:默认的返回值为 0 表示函数执行成功了,返回值为非 0 表示函数执行失败(出错)了。if、while、for 等语句都是根据函数的退出状态来判断条件是否成立。函数执行失败时,我们可以自定义return返回值,这样就可以根据返回值(退出状态)来判断具体出现了什么错误,比如一个打开文件的函数,我们可以指定 1 表示文件不存在,2 表示文件没有读取权限,3 表示文件类型不对。
案例
1>定义return返回的状态码
#!/bin/bash
function test() {
echo "arg=$1"
if [ $1 == 1 ]; then
return 111
else
return 100
fi
}
test 1
echo "该函数的执行状态值为$?"
输出
[root@ali01 ~]# bash func6.sh 22
arg=10
该函数的执行状态值为100
[root@ali01 ~]# vim func6.sh
[root@ali01 ~]# bash func6.sh 22
arg=1
该函数的执行状态值为111
8.6.2 echo 返回值 – 获取函数处理后的结果
案例
#!/bin/bash
function blreturn(){
echo "这个函数会对输入的两个数字进行相加运算..."
echo "输入第一个数字: "
read aNum
echo "输入第二个数字: "
read anotherNum
echo "两个数字分别为 $aNum 和 $anotherNum !"
return $(($aNum+$anotherNum))
}
blreturn
echo "输入的两个数字之和为 $? !"
输出
[root@ali01 ~]# ./function3.sh
这个函数会对输入的两个数字进行相加运算...
输入第一个数字:
34
输入第二个数字:
12
两个数字分别为 34 和 12 !
输入的两个数字之和为 46 !
函数返回值在调用该函数后通过 $? 来获得。
8.7 函数参数
$0 取脚本的文件名及路径
$1,$2 给脚本传参数
$* 把一堆参数集合成一个参数,传给脚本
$# 一共传了多少个参数
$$ 脚本的pid
$? 上一个脚本执行的返回值
$@ 与$*类似,区别是每个参数是分开的
8.7.1 案例
1>打印位置参数的值
#!/bin/bash
function parm(){
echo "第一个参数为 $1 !"
echo "第二个参数为 $2 !"
echo "第十个参数为 $10 !"
echo "第十个参数为 ${10} !"
echo "第十一个参数为 ${11} !"
echo "参数总数有 $# 个!"
echo "作为一个字符串输出所有参数 $* !"
}
parm 1 2 3 4 5 6 7 8 9 34 73
输出
[root@ali01 ~]# bash function4.sh
第一个参数为 1 !
第二个参数为 2 !
第十个参数为 10 !
第十个参数为 34 !
第十一个参数为 73 !
参数总数有 11 个!
作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73 !
**注意:**当n>=10时,需要使用${n}来获取参数。
2>数组传参
#!/bin/bash
arr=(1 2 3 4 5)
get_sum() {
sum=0
for i in $*;do
let sum+=i
done
echo $sum
}
echo "get the array sum is `get_sum ${arr[@]}`"
输出
[root@ali01 ~]# ./func5.sh
get the array sum is 15
3>判断网址是否正常运行
#!/bin/bash
function chuancan() { #定义一个chuancan函数提醒用户输入一个网址
echo "$0 请输入一个网址" #取脚本的文件名及路径及请输入一个网址!
exit 1
}
function jc_url() { #定义一个jc_url的函数检测用户输入参数是否正确及检测结果
wget $1 &>/dev/null #若用户输入传参数是正确的,就执行wget命令
if [ "$?" -eq 0 ] #判断以上命令执行是否有误
then
echo "$1 Httpd is Running... " #若判断以上命令无误,输入用户传参数及检测结果
else
echo "$1 Httpd is Stoped..." #若判断以上命令有误,输出用户传参数及检测结果
exit 1
fi
}
function panduan() { #定义最后结果的函数
if [ "$#" -ne 1 ] #如果用户输入的传参数不是1
then #那么
chuancan #调用chuancan函数
fi
jc_url $1 #如果用户输入的传参数是1,那么就调用jc_url 函数
}
panduan $* #把命令行接收的所有参数传给函数内部
输出
[root@localhost ~]# bash func2.sh www.baidu.com
www.baidu.com Httpd is Running...
4>检查web服务是否启动
1、检查web服务是否启动
#!/bin/sh
. /etc/init.d/functions
start_nginx=/application/nginx/sbin/nginx
USAGE()
{
echo "USAGE $0 {start|stop|restart}"
exit 1
}
if [ $# -ne 1 ]
then
USAGE
fi
if [ "$1" == "start" ]
then
$start_nginx
action "start nginx" /bin/true
elif [ "$1" == "stop" ]
then
killall nginx
action "stop nginx" /bin/true
elif [ "$1" == "restart" ]
then
pkill nginx
sleep 2
$start_nginx
action "restart nginx" /bin/true
else
USAGE
exit 1
fi
9 expect
TCL(Tool command language)是一种类似shell脚本的语言,你可以使用它来完成许多操作。expect是从它发展出来的。如果你想要写一个能够自动处理输入输出的脚本(如向用户提问并且验证密码)又不想面对C或者Perl,那么expect是你的最好的选择
expect是在tcl基础上创建起来的,它还提供了一些tcl所没有的命令,它可以用来做一些linux下无法做到交互的一些命令操作
9.1 安装
[root@localhost shell]# yum -y install expect
9.2 使用expect
1)定义脚本执行的shell
#!/usr/bin/expect
这里定义的是expect可执行文件的链接路径(或真实路径),功能类似于bash等shell功能
2)set timeout 30
设置超时时间,单位是秒,如果设为timeout -1 意为永不超时
3)spawn
spawn 是进入expect环境后才能执行的内部命令,如果没有装expect或者直接在默认的SHELL下执行是找不到spawn命令的。不能直接在默认的shell环境中进行执行主要功能,它主要的功能是给ssh运行进程加个壳,用来传递交互指令。
4)expect
这里的expect同样是expect的内部命令
主要功能:判断输出结果是否包含某项字符串,没有则立即返回,否则就等待一段时间后返回,等待时间通过timeout进行设置
5)send
执行交互动作,将交互要执行的动作进行输入给交互指令
命令字符串结尾要加上**"\r"**,如果出现异常等待的状态可以进行核查
6)exp_continue
继续执行接下来的交互操作
7)interact
执行完后保持交互状态,把控制权交给控制台;如果不加这一项,交互完成会自动退出
8)$argv
expect 脚本可以接受从bash传递过来的参数,可以使用 [lindex $argv n]获得,n从0开始,分别表示第一个,第二个,第三个……参数
9.3 案例
1>无交互登录服务器创建新用户
#!/usr/bin/expect
# set host ip
set ipaddress "192.168.1.101"
#set loginuser
set name "root"
#set password
set passwd "1"
#set timeout
set timeout 30
#spawn
spawn ssh $name@$ipaddress
expect {
"yes/no" { send "yes\r";exp_continue }
"password" { send "$passwd\r" }
}
#interact
expect "#"
send "useradd user1\r"
send "pwd\r"
send "touch /opt/hello.txt\r"
send "exit\r"
expect eof
10 数组
10.1定义
数组的特性就是一组数据类型相同的集合(不包括有一些编程语言提出来的关联数组的概念)
数组中可以存放多个值。Bash Shell 只支持一维数组(不支持多维数组)
与大部分编程语言类似,数组元素的下标由 0 开始。
10.2基本数组
10.2.1 基本数组定义
1>数值类型:一对括号表示数组,数组中元素之间使用“空格”来隔开。
arr_number=(1 2 3 4 5);
2>字符串类型:使用一对括号表示数组,其中数组中的元素使用双引号或者单引号包含,同样使用“空格”来隔开。
array_name=(value1 value2 ... valuen)
arr_string=("abc" "edf" "sss"); 或者 arr_string=('abc' 'edf' 'sss');
user=(`cat /etc/passwd|cut -d: -f1`)
stu=(lisa tom jarry "miss zhang")
读取数组
${array_name[index]}
10.2.2 实例
1>定义数组
方法一:一次定义一个
[root@localhost shell]#arr[0]=1
[root@localhost shell]#arr[1]=2
[root@localhost shell]#arr[2]=3
[root@localhost shell]#arr[3]=4
方法二:一次定义多个
[root@localhost shell]# arr1=(1 2 3 4)
2>读取数组中的元素
[root@itbest shell]# echo ${arr[0]}
1
[root@itbest shell]# echo ${arr[1]}
2
[root@itbest shell]# echo ${arr[2]}
3
[root@itbest shell]# echo ${arr[3]}
4
3>数组中替换元素的值
[root@localhost shell]# arr2=(1 2 3 4)
[root@localhost shell]# echo ${arr2[*]}
1 2 3 4
[root@localhost shell]# arr2[1]=5
[root@localhost shell]# echo ${arr2[*]}
1 5 3 4
4>数组中增加新元素的值
[root@localhost shell]# arr2=(1 2 3 4)
[root@localhost shell]# arr2[6]=5
[root@localhost shell]# echo ${arr2[*]}
1 2 3 4 5
注意:当添加的元素的长度大于已存在的数组的长度时,默认值时添加在组数的最后
5>删除数组中的值
[root@localhost shell]# unset arr2[1]
[root@localhost shell]# echo ${arr2[*]}
1 3 4
[root@localhost shell]#
[root@localhost shell]# unset arr2 --清除整个数组的值
[root@localhost shell]# echo ${arr2[*]}
6>数组的切片
[root@localhost ~]# arr3=(1 2 3 4)
[root@localhost ~]# echo ${arr3[*]:1}
2 3 4
[root@localhost ~]# echo ${arr3[@]:1}
2 3 4
10.3 关联数组
10.3.1定义关联数组
方法一:声明关联数组(一次赋一个值)
#声明一个关联数组
declare -A ass_array1
ass_array1[name]='zhangsan'
ass_array1[age]=20
#执行结果
echo ${ass_array1[name]}
方法二:声明关联数组(一次赋多个值)
#声明一个关联数组
declare -A ass_array2
ass_array2=([name]=lisi [age]=30)
echo ${ass_array2[name]}
执行结果
#执行结果
[root@localhost ~]# bash ass_arr1.sh
lisi
[root@localhost ~]#
10.3.2查看关联数组
1>查看关联数组
[root@localhost ~]# declare -A ass_array2
[root@localhost ~]# ass_array2=([name]=lisi [age]=30)
[root@localhost ~]# declare -A ##查看关联数组
declare -A BASH_ALIASES='()'
declare -A BASH_CMDS='()'
declare -A ass_array2='([name]="lisi" [age]="30" )'
2>访问数组元素
[root@localhost ~]# echo ${ass_array2[name]} ##访问下标为name的元素
lisi
[root@localhost ~]# echo ${ass_array2[@]} ##获取所有的元素
lisi 30
[root@localhost ~]# echo ${#ass_array2[@]} ##获取元素的个数
2
[root@localhost ~]# echo ${!ass_array2[@]} ##获取索引
name age
10.3.3实战案例
1>学生信息查询系统
#!/bin/bash
for((i=0;i<3;i++))
do
read -p "输入第$((i+1))个人名:" name[$i]
read -p "输入第$[$i+1]个年龄:" age[$i]
read -p "输入第`expr $i + 1`个性别:" gender[$i]
done
clear
echo -e "\t\t\t学生信息查询系统"
while :
do
read -p "输入要查询的姓名:" xm
[ $xm == "q" ] && exit
for((i=0;i<3;i++))
do
if [ "$xm" == "${name[$i]}" ];then
echo "姓名:${name[$i]} 年龄:${age[$i]} 性别:${gender[$i]}"
fi
done
done
2> 统计web网站的不同状态连接数
#!/bin/bash
declare -A array1
# 统计连接数个数
#states=$(netstat -antup |grep 80|awk -F" " '{print $6}')
states=$(ss -ant|grep 80|cut -d ' ' -f1)
for i in $states
do
let array1[$i]++
done
#遍历打印数组中的索引和元素的个数
for j in ${!array1[@]}
do
echo $j:${array1[$j]}
done
3>遍历列表中的水果
#!/bin/bash
# 定义一个数组变量
fruits=("苹果" "香蕉" "橙子" "葡萄" "西瓜")
# 循环遍历数组元素
for fruit in "${fruits[@]}"
do
echo "水果: $fruit"
done
# 获取数组的长度
length=${#fruits[@]}
echo "数组的长度: $length"
# 获取数组的特定元素
echo "第一个水果: ${fruits[0]}"
echo "最后一个水果: ${fruits[length-1]}"
# 修改数组元素
fruits[2]="草莓"
echo "修改后的数组: ${fruits[@]}"