数组,逻辑判断以及循环
1. 概述
大家好,我又来了。今天呢我们继续学习shell相关的知识。还是老样子我们先回顾下上一次【脚本交互 以及表达式】学习到的知识
- 登录shell 关联配置文件
- 什么是子shell
- umask 修改默认权限
- read 基础
- 表达式
- 简单计算表达式
- expr 计算
- bc 计算
- 测试 表达式
- 逻辑表达式
- 字符串表达式
- 文件表达式
- 数字表达式
- 测试进阶表达式
- 逻辑组合表达式
我们简单回顾了下上次学习的内容。废话不多说了,接下来让我们一起学习新的内容
2. 数组
2.1 格式定义
格式
# 在Shell中,用括号来表示数组,数组元素用“空格”符号分割开。定义数组的语法格式:
array_name=(value1 ... valuen)
格式解读
单行定义
array_name=(value0 value1 value2 value3)
多行定义
array_name=(
value0
value1
value2
value3
)
单元素定义
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
2.2 具体案例
单行定义案例
[vagrant@localhost test003]$ echo ${array1}
[vagrant@localhost test003]$ array1=(11 22 33 44 55)
[vagrant@localhost test003]$ echo ${array1}
11
[vagrant@localhost test003]$ echo ${array1[@]}
11 22 33 44 55
[vagrant@localhost test003]$
多行定义案例
[vagrant@localhost test003]$ echo ${array2[@]}
[vagrant@localhost test003]$ array2=()
[vagrant@localhost test003]$ array2=(
> aa
> bb
> cc
> dd
> )
[vagrant@localhost test003]$ echo ${array2[@]}
aa bb cc dd
[vagrant@localhost test003]$
单元素定义案例
[vagrant@localhost test003]$ echo ${array3[@]}
[vagrant@localhost test003]$ array3[0]=bb
[vagrant@localhost test003]$ array3[1]=ff
[vagrant@localhost test003]$ array3[2]=ee
[vagrant@localhost test003]$ echo ${array3[@]}
bb ff ee
[vagrant@localhost test003]$
命令行定义案例
[vagrant@localhost test003]$ echo ${array4[@]}
[vagrant@localhost test003]$ array4=$(ls ../)
[vagrant@localhost test003]$ echo ${array4[@]}
test001 test002 test003
[vagrant@localhost test003]$
2.3 多种取值方式
格式
基于索引找内容
读取数组元素值可以根据元素的下标值来获取,语法格式如下:
${array_name[index]}
${array_name[@]:起始位置:获取数量}
注意:
获取具体的元素内容,指定其下标值,从0开始
获取所有的元素内容,下标位置写"@"或者"*"
实例
[vagrant@localhost test003]$ num_list=(123 234 345 456 567)
[vagrant@localhost test003]$ echo ${num_list[@]}
123 234 345 456 567
[vagrant@localhost test003]$ echo ${num_list[@]:1:3}
234 345 456
[vagrant@localhost test003]$
2.4 获取数组长度
格式
在变量前面添加符号#
${#num_list[0]}
实例
[vagrant@localhost test003]$ echo ${num_list[@]}
123 234 345 456 567
[vagrant@localhost test003]$ echo ${#num_list[@]}
5
[vagrant@localhost test003]$
2.5 获取系统所数组
格式
declare -a
具体实例
[vagrant@localhost test003]$ declare -a
declare -a BASH_ARGC='()'
declare -a BASH_ARGV='()'
declare -a BASH_LINENO='()'
declare -ar BASH_REMATCH='()'
declare -a BASH_SOURCE='()'
declare -ar BASH_VERSINFO='([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="x86_64-redhat-linux-gnu")'
declare -a DIRSTACK='()'
declare -a FUNCNAME='()'
declare -a GROUPS='()'
declare -a PIPESTATUS='([0]="0")'
declare -a array1='([0]="11" [1]="22" [2]="33" [3]="44" [4]="55")'
declare -a array2='([0]="aa" [1]="bb" [2]="cc" [3]="dd")'
declare -a array3='([0]="bb" [1]="ff" [2]="ee")'
declare -a num_list='([0]="123" [1]="234" [2]="345" [3]="456" [4]="567")'
[vagrant@localhost test003]$
2.6 数组替换/ 数组删除
格式
元素内容替换:
array_name[index]=值
注意:
在修改元素的时候,index的值一定要保持准确
元素部分内容替换,可以参考字符串替换格式:
${array_name[index]/原内容/新内容}
注意:
默认是演示效果,原数组未被修改,如果真要更改需要结合单元素内容替换
删除单元素
unset array_name[index]
删除整个数组
unset array_name
具体案例
[vagrant@localhost test003]$ unset array6
[vagrant@localhost test003]$ array6=(11 22 aa bb cc ddd ggg)
[vagrant@localhost test003]$ echo ${array6}
11
[vagrant@localhost test003]$ echo ${array6[@]}
11 22 aa bb cc ddd ggg
[vagrant@localhost test003]$ array6[0]=99
[vagrant@localhost test003]$ echo ${array6[@]}
99 22 aa bb cc ddd ggg
[vagrant@localhost test003]$ array6[5]=${array6[5]/ddd/ert}
[vagrant@localhost test003]$ echo ${array6[@]}
99 22 aa bb cc ert ggg
[vagrant@localhost test003]$ unset array6[5]
[vagrant@localhost test003]$ echo ${array6[@]}
99 22 aa bb cc ggg
[vagrant@localhost test003]$ unset array6
[vagrant@localhost test003]$ echo ${array6[@]}
[vagrant@localhost test003]$
3. 逻辑判断
3.1 if 判断
3.1.1 格式
单分支格式
单路决策 - 单分支if语句
样式:
if [ 条件 ]
then
指令
fi
特点:
单一条件,只有一个输出
双分支格式
双路决策 - 双分支if语句
样式:
if [ 条件 ]
then
指令1
else
指令2
fi
特点:
单一条件,两个输出
多分支格式
多路决策 - 多分支if语句
样式:
if [ 条件 ]
then
指令1
elif [ 条件2 ]
then
指令2
else
指令3
fi
特点:
n个条件,n+1个输出
单行格式
单行命令写法
if [ 条件1 ]; then 指令1; elif [ 条件2 ]; then 指令2; ... ; else 指令n; fi
3.1.2 实例
单行实例
#!/bin/bash
# 单个if 判断
gender="$1"
if [ "${gender}" == "男" ]
then
echo "你是男的"
exit
fi
echo "你不是男的"
双分支实例
#!/bin/bash
# 双分支实例
gender="$1"
if [ "${gender}" == "nan" ]
then
echo "你是男的"
else
echo "你是女的"
fi
多分支实例
#!/bin/bash
# 多分支实例
gender="$1"
if [ "${gender}" == "nan" ]
then
echo "你是男的"
elif [ "${gender}" == "nv" ]
then
echo "你是女的"
else
echo "我不知道你的性别"
fi
3.1.3 经典实例
3.1.3.1 奇偶数 判断
#!/bin/bash
# 计算判断
# 引导客户输入一个数字
read -p "请输入一个数字" num
# 判断是基数 还是 偶数
if (( ${num} % 2 == 0 ))
then
echo "你是偶数"
else
echo "你是奇数"
fi
3.1.3.2 正则 判断
#!/bin/bash
# 表示正则判断
read -p "您输入一个字符串: " string
if [[ ${string} == v* ]]
then
echo "你是满足以v开头的"
else
echo "你不满足以v开头"
fi
3.2 case 判断
格式
case 变量名 in
值1)
指令1
;;
...
值n)
指令n
;;
esac
实例
#!/bin/bash
# 进行case 练习判断
type="$1"
case ${type} in
"1")
echo "你是1"
;;
"2")
echo "你是2"
;;
*)
echo "你是几我也不知道"
;;
esac
3.3 for 循环
格式
循环逻辑语法解析:
关键字 [ 条件 ]
do
执行语句
done
注意:
这里的关键字主要有四种:
for - 循环遍历一个元素列表
while - 满足条件情况下一直循环下去
until - 不满足条件情况下一直循环下去
select - 一种特殊的循环遍历,侧重于遍历用户输入,一般结合case等语句使用
实例1:遍历命令列表
#!/bin/bash
# 进行for循环
for i in $(ls /)
do
echo "您的路径是${i}"
done
实例2:遍历参数列表
查看脚本内容
[root@localhost ~]# cat for_arg_list.sh
#!/bin/bash
# 功能:脚本参数列表 for循环
for i in $@
do
echo "列表元素: ${i}"
done
脚本执行后效果
[root@localhost ~]# /bin/bash for_arg_list.sh 1 2 3
列表元素: 1
列表元素: 2
列表元素: 3
3.3.1 多种案例
案例1
#!/bin/bash
# 进行循环案例
for i in yuwen shuxue lishi
do
echo "列表元素: ${i}"
done
案例2
#!/bin/bash
# 循环
for i in {1..3}
do
echo "元素内容是: ${i}"
done
案例3
#!/bin/bash
# 实现脚本参数遍历
for i in $@
do
echo "元素内容是: ${i}"
done
3.3.2 综合实践
随机生成用户
#!/bin/bash
# 随机创建用户
user_file="/tmp/user.txt"
# 检查是否是文件
[ -f ${user_file} ] && > ${user_file}
# 开始批量创建用户
for i in {1..5}
do
# 创建密码
pwd="aaa$RANDOM"
# 创建用户
sudo useradd user-${i}
# 设置密码
echo ${pwd} | passwd --stdin user-${i} > /dev/null 2>&1
# 开始输出信息
echo "创建账号是: user-${i}, 该用户的密码是: ${pwd}"
echo -e "创建的账号是: \033[31;41muser-${i}\033[0m 该用户的密码是: \033[31;41m${pwd}\033[0m"
done
#!/bin/bash
# 进行批量的用户删除
for i in {1..5}
do
sudo userdel -r user-${i}
echo "用户【user-${i}】删除成功"
done
对特定的网段的主机进行扫描
#!/bin/bash
# 对特定ip进行扫描
base_net=192.168.56
net_file='/tmp/host.txt'
# 判断文件是否存在
if [ -f ${net_file} ]
then
sudo echo '' > ${net_file}
fi
for i in {1..100}
do
# 开始检测主机
host_status=$(ping -c1 -W1 ${base_net}.${i} > /dev/null 2>&1 && echo "UP" || echo "DOWN")
sudo echo "${base_net}.${i} 主机状态: ${host_status}" >> ${net_file}
sudo echo "${base_net}.${i} 主机状态: ${host_status}"
done
# 输出信息
live_num=$(grep UP ${net_file} | wc)
unlive_num=$(grep DOWN ${net_file} | wc)
echo -e "\e[31m${netsub}.0 网段主机存活情况\e[0m"
echo "------------------------------------"
echo -e "\e[32m${netsub}.0 网段存活主机数量: ${live_num}\e[0m"
echo -e "\e[32m${netsub}.0 网段异常主机数量: ${unlive_num}\e[0m"
3.3.3 循环赋值
#!/bin/bash
# 进行循环赋值
all_sum=0
odd_sum=0
even_sum=0
for i in {1..100}
do
let all_sum+=i
done
for i in {1..100..2}
do
let odd_sum+=i
done
for i in {0..100..2}
do
let even_sum+=i
done
echo -e "所有的数字之和是: \033[31m${all_sum}\033[0m"
echo -e "所有的数字之和是: \033[31m${odd_sum}\033[0m"
echo -e "所有的数字之和是: \033[31m${even_sum}\033[0m"
3.3.4 (())
版的双括号的语法
#!/bin/bash
# 使用特殊符号(()) 来进行计算
all_sum=0
for ((i=0; i<=100; i+=1))
do
let all_sum+=i
done
echo -e "计算结果是: \033[31m${all_sum}\033[0m"
3.3.4.1 综合实践:命令行进度条数字
#!/bin/bash
# 实现数字进度条
for ((i=0; i<=100; i+=1))
do
// 防止信息输出的叠加,采用\e[4D,每次输出信息的时候,光标左移4个位置,信息不会出现叠加
printf "\e[4D%3d%%" $i
sleep 0.1
done
3.3.4.2 综合实践:实现进度条
#!/bin/bash
# 实现数字进度条
str="#"
arr=("|" "/" "-" "\\")
for ((i=0; i<=50; i+=1))
do
let index=i%4
printf "[%-50s][%d%%]%c\r" "$str" "$(($i*2))" "${arr[$index]}"
sleep 0.2
str+="#"
done
echo ""
3.3.4.3 综合实践:保存数字最大值 以及最小值
#!/bin/bash
# 设定随机数比大小
# 设定基本变量
declare -i min max
declare -a nums
# 设定大小比较
for ((i=0;i<10;i++))
do
# 将随机数添加到数组中
nums[$i]=$RANDOM
# 设定初始值
[ $i -eq 0 ] && min=${nums[0]} max=${nums[0]}
# 设定最大值
[ ${nums[$i]} > $max ] && max=${nums[$i]}
# 设定最小值
[ ${nums[$i]} < $min ] && min=${nums[$i]}
done
echo -e "\e[31m 随机数的统计信息\e[0m"
echo "------------------------------"
echo -e "\e[32m所有的随机数:${nums[@]}"
echo -e "最大的随机数:${max}"
echo -e "最小的随机数:${min}\e[0m"
3.4 while 循环
基础语法
场景:只要条件满足,就一直循环下去
while [ 条件判断 ]
do
执行语句
done
具体实例
#!/bin/bash
# 通过while 循环来执行
all_num=0
odd_num=0
even_num=0
i=0
while (( i <= 100 ))
do
let all_num+=i
let i++
done
i=0
while ((i<=100))
do
((odd_num+=i))
((i+=2))
done
i=1
while ((i<=100))
do
((even_num+=i))
((i+=2))
done
echo "累加的和是:${all_num}"
echo "奇数累加的和是: ${odd_num}"
echo "偶数累加的和是: ${even_num}"
3.4.1 while read 用法
格式
while中有一种特殊的语法,while read line 它可以从文本中逐行读取相关的内容,然后存储到一个临时变量line中,然后我们后续就可以逐行对文本内容进行操作
样式1: cat提前读
cat a.log | while read line
do
echo "File: ${line}"
done
实例1
#!/bin/bash
# 通过while read 逐行读取
i=0
env | while read line
do
((i+=1))
echo "第${i}行内容是: ${line}"
done
实例2
exec 0< a.log
while read line
do
echo "${line}"
done
实例3
while read line
do
echo "File: ${line}"
done < a.log
3.5 until循环
使用方式跟while保持一致。
格式
场景:只要条件不满足,就一直循环下去
until [ 条件判断 ]
do
执行语句
done
3.6 select 条件选择
语法格式
select 变量名 in input_list
do
循环语句
done
语法解读:
1 select 从 input_list 获取相关的值,然后输出到一个菜单列表,元素格式如下:
序号) 菜单条目
2 用户输入信息的标识使用PS3 的值,默认值是#?。
我们可以定制PS3环境变量
3 如果用户输入菜单序号,则输出菜单内容
4 select的退出方式有很多种
强制退出:Ctrl+D 组合键
普通退出:结合break方式
实例1
#!/bin/bash
# 通过select 进行简单选择
echo "您喜欢的系统是:"
select osname in "HarmonyOS" "Linux" "Windows" "Ubuntu"
do
echo "您选择的系统是: ${osname}"
exit
done
实例2
#!/bin/bash
# 修改输入指令
PS3='请选择菜单序号: '
echo "请输入您喜欢的系统: "
select osname in "os" "linux" "window"
do
echo "您选择的操作系统是: ${osname}"
exit
done