shell 循环、数组与函数
循环
一、shell 循环:for
1、语法
for 循环开始时,会对变量 i 进行赋值,并执行 do 和 done 之间的代码,在第一次循环后,对 i 再次赋值
2、循环测试 ip 连通性
测试 192.168.198.1 - 192.168.198.3 的连通性
-W1:等待1秒钟,无法 ping 通则放弃
for i in {1..3}
do
ip=192.168.198.$i
ping -c1 -W1 $ip &> /dev/null
if [ $? -eq 0 ]
then echo "$ip" | tee -a ip.txt
fi
done
测试结果:
3、循环创建用户
要求:
用户使用参数形式,通过读取自定义用户名文件来创建用户;
如果用户没有输入用户名文件,提示用户输入;
如果用户输入的不是文件,提示用户更正;
用户存在,提示存在 ;用户不存在,则创建用户。
#!/bin/bash
#用户初始化密码
password=123
#判断脚本是否有参数
if [ $# -eq 0 ] ; then
echo "未检测到文件"
exit
fi
#判断用户输入的是否为文件
if [ ! -f $1 ] ; then
echo "文件名错误"
exit
fi
#设置循环,读取文件,创建用户
for user in `cat $1`
do
id $user &> /dev/null
#用户不存在,创建用户;否则提示已存在
if [ $? -eq 0 ]; then
echo "$user 用户已存在"
else
useradd $user
echo "$password" | passwd --stdin $user &> /dev/null
#判断用户是否创建成功
if [ $? -eq 0 ] ; then
echo "$user 创建成功"
fi
fi
done
测试结果:
二、shell 循环:while、until
1、while 语法结构:
退出循环的三种命令:
exit:退出整个程序
break:退出当前循环程序
continue:退出本次循环,执行下一次循环
● 示例:要求用户输入密码,验证密码的一致性,只有三次输入密码的机会:
① for 循环:
read -s -p: -s:不显示密码
#!/bin/bash
for i in {1..3}
do
read -s -p "请输入密码:" pass1
echo ""
read -s -p "请确认密码:" pass2
echo ""
if [ $pass1 = $pass2 ];then
echo "密码已设置"
exit
else
echo "两次输入的密码不同"
fi
done
② while 循环:
let i++:循环次数加1
#!/bin/bash
while :
do
read -s -p "请输入密码:" pass1
echo ""
read -s -p "请确认密码:" pass2
echo ""
if [ $pass1 = $pass2 ];then
echo "密码已设置"
exit
else
echo "两次输入的密码不同"
let i++
if [ $i -eq 3 ];then
exit
fi
fi
done
2、until 语法结构:
示例:每秒显示一个数字,到 7 时停止
3、expect
(1) 作用:
根据程序的提示模拟标准输入,提供给程序所需要的输入内容,解决脚本与程序需要交互的问题。
(2) 安装:
yum install -y expect tcl tclx tcl-devel
(3) expect 解决 ssh 交互问题
① 编写 expect 脚本
vim ssh.exp (注意后缀是 exp,不是 sh)
spawn:expect 内部命令,启动一个 shell 程序
expect { 期望的内容 }
exp_continue:这一行的内容如果没有则跳过
interact:允许用户自己操作
② 授权后验证
chmod +x ssh.exp
执行 .exp 文件:
./ssh.exp 或 expect ssh.exp
数组与函数
一、数组
1、数组简介
(1) 变量:用一个固定的字符串,代表一个不固定的字符串;
${name:2:2} 变量名: 起点: 步长
(2) 数组:用一个固定的字符串,代表多个不固定的字符串。
2、数组类型
(1) 普通数组:只能使用整数作为数组索引
① 定义方法:
● 定义方法1:一次定义一个值:数组名 [下标]=变量值
查看方法:默认输出值 ;! 表示取反,输出索引值
● 定义方法2:一次赋多个值:数组名=(变量值1,变量值2 …)
例1:array=(`cat/etc/passwd`):将目录里的内容赋值给数组
例2:数组可调用变量:
② 查看方法:
echo ${数组名[@]} ; declare -a | grep 数组名
(2) 关联数组:可以使用字符串作为数组索引
关联数组在使用前需要先声明:declare -A + 数组名
定义方法:数组名 [索引]=变量值 ; 一次赋多个值
3、数组示例:
(1) for 循环定义数组
先准备一个测试文件:
编写脚本将文件放入数组中:
for i in ${!array[*]}:通过索引遍历值
#!/bin/bash
#定义数组
for a in `cat /etc/array`
do
array[i++]=$a
done
#调用数组,查看
for i in ${!array[*]}
do
echo "第 $i 个索引,值是:${array[$i]}"
done
测试结果:
(2) 数组统计性别
① 定义性别文件:
② 编写脚本
● declare -A sex:声明为关联数组
● while read line do … done < sex.txt
脚本读取 sex.txt 的内容,将读取的每一行文本赋值给 line
● type=`echo $line | awk '{print $2}'`
切片索引值为 2 的一列(性别列)
● let sex[$type]++
根据值的不同,分成 sex[m] 和 sex[f] 两个数组
#!/bin/bash
declare -A sex
while read line
do
type=`echo $line | awk '{print $2}'`
let sex[$type]++
done < sex.txt
for i in ${!sex[@]}
do
echo "$i:${sex[$i]}"
done
测试结果:
(3) IFS=$'\n'
for 循环的默认分隔符是空格,使用 IFS=$'\n' 命令可以将 for 循环的分隔符定义成回车。
#!/bin/bash
IFS=$'\n'
for i in `cat /etc/hosts`
do
hosts[a++]=$i
done
for i in ${!hosts[@]}
do
echo "$i,${hosts[$i]}"
done
测试结果:
OLD_IFS=$IFS:保留原有的分隔方式,方便后续 for 循环的分隔。
二、函数
1、概念:
一段完成特定功能的代码片段。
2、函数的定义和调用
定义方法一:
定义方法二:
调用:直接写出函数名
3、阶乘函数
fun1 (){
result=1
for ((i=1;i<=$1;i++))
do
result=$[$result*$i]
done
echo "$1 的阶乘是 $result"
}
#位置变量,接收用户写入的参数
fun1 $1
测试结果:
4、数组传参
#!/bin/bash
num=(1 2 3 4)
array() {
#声明局部变量
local j
#遍历数组中的数
for i in $*
do
newarray[j++]=$[$i+5]
done
echo ${newarray[*]}
}
#调用函数传入数组
array ${num[*]}