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[*]}