基于数组的shell脚本编写

本文介绍 Bash Shell 中数组的基本操作与字符串处理方法,包括数组声明、元素赋值、引用、切片等,同时讲解了字符串切片、模式匹配、大小写转换等实用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据:变量,文件,数组

变量:存储单个元素的内存中的一块存储空间

数组:存储多个元素的内存中的连续的内存空间,数组有数组名,且索引编号从0开始。

数据结构中逻辑结构:集合、线性、树形、图形

数据结构中物理结构(也叫做存储结构):顺序、链式、索引、散列

bash shell 中的数组属于线性表,体现为所有元素的内存地址是连续的

声明一个数组

declare-a NAME:声明索引数组(索引是数值)

declare-A NAME:声明关联数组(索引是字符串)

  • 数组中元素的赋值方式
    • 1)一次只赋值一个元素
      • arr[0]=hello
    • 2)一次赋值全部元素
      • arr=(“hello” “nihao” “who” )
    • 3)只赋值特定元素
      • arr=([0]=”nihao” [3]=”hello”)
      • 注意:bash支持稀疏格式的数组
    • 4read -a arr
  • 引用数组中元素的方式:通过索引取值
    • ${arr[1]}
    • 数组中元素的索引是从0开始的,${arr[1]}表示取的是第二个元素的值
    • 注意:引用时,只给数组名,表示引用下标为0的元素。例如:$arr == ${arr[0]}
  • 获取数组的长度(数组中元素的个数)
    • ${#arr[*]}
    • ${#arr[@]}
  • 获取数组中的全部元素
    • ${arr[*]}
    • ${arr[@]}
  • 示例:生成10个随机数,并找出其中的最大值和最小
    declare -a rand
    declare -i max=0
    declare -i min=1000000

    for i in {0..9}; do
        rand[$i]=$RANDOM       # $RANDOM
    的值是一个随机数
        echo ${rand[$i]}
        [ ${rand[$i]} -gt $max ] && max=${rand[$i]}
        [ ${rand[$i]} -lt $min ] && min=${rand[$i]}
    done

    echo "The  MAX number is $max"
    echo "The  MIN number is $min"

冒泡排序算法演示(对于循环语句的选取不限为while循环或for循环)#!/bin/bash
declare -a rand
declare -i rand_length
declare -i var

#
生成10个随机数
for i in {0..9}; do
    rand[$i]=$[ $RANDOM%100 ]       # $RANDOM
的值是一个随机数
done
echo ${rand[*]}
rand_length=${#rand[*]}
# echo $rand_length

#
开始写冒泡排序
for i in `seq 0 $[ $rand_length-1] | sort -n -r`;do
    for((j=0;j<$i;j++));do
    if [ ${rand[j]} -gt ${rand[$[j+1 ]]} ];then
        var=${rand[j]}
        rand[j]=${rand[$[ j+1 ]]}
        rand[$[ j+1 ]]=$var
    fi
    done
   #echo ${rand[*]}
done
echo -e "\E[1;31m${rand[*]} \033[0m"

  • 练习:写一个脚本,定义一个数组,数组中的元素是/var/log/目录下所有的以.log结尾的文件名,统计其下标为偶数的文件中的行数之和
    declare -a files
    files=(/var/log/*.log)
    declare -i lines=0
    for i in $(seq 0 $[${#files[*]}-1]); do
        if [ $[$i%2] -eq 0 ]; then
            let lines+=$(wc -l ${files[$i]} | cut -d' ' -f1)
        fi
    done
    echo "Lines: $line
    s.
  • 数组的其他功能
    • 数组元素切片
      • 例如:${file[*]:2:3}:表示在显示file中的全部元素的时候,跳过前两个元素,显示后面一个元素

·        [root@localhost test]# arr=(1 23 4)

·        [root@localhost test]# echo${arr[*]}

·        1 2 3 4

·        [root@localhost test]# echo${arr[*]:2 :1}

·        3

      •  
    • 向非稀疏格式的数组中追加元素
      • 例如:arr[${#arr[*]}]=hello

·        [root@localhost test]# echo${#arr[*]}

·        4

·        [root@localhost test]#arr[${#arr[*]}]=hello

·        [root@localhost test]# echo${arr[*]}

·        1 2 3 4 hello

      •  
    • 删除数组中的某个元素
      • 例如:unset arr[2]
    • 关联数组的赋值
      • 例如:declare -A arr(注意关联数组需要首先声明), arr=([a]=”nihao” [b]=”nima” [c]=”nidaye”)

·        [root@localhost test]# declare-A small

·        [root@localhost test]#small=([mo]=1 [ku]=2)

·        [root@localhost test]# echo${small[mo]}

·        1

·        [root@localhost test]# echo${small[ku]}

·        2

·        bash的内置字符串处理工具(了解)

    •  

字符串切片,对于变量而言

      • 例如:name=nihaoma , echo ${name:2:3} 打印的结果为:hao
      • 例如:name=nihaoma , echo ${name: -4} 打印的结果为:aoma
    • 基于模式取字符串,对于变量而言
      • ${var#*word}:其中word是指定的分隔符。功能:自左向右,查找var变量所存储的字符串中,第一次出现的word分隔符,删除字符串开头至此分隔符处的所有字符
        • 例如:path="/var/log/yhy.txt" , echo ${path#*/} 打印结果为:var/log/yhy.txt
      • ${var##*word}:其中word是指定的分隔符。功能:自左向右,查找var变量所存储的字符串中,最后一次出现的word分隔符,删除字符串开头至此分隔符处的所有字符
        • 例如:path="/var/log/yhy.txt" , echo ${path##*/} 打印结果为:yhy.txt
      • ${var%word*}:其中word是指定的分隔符。功能:自右向左,查找var变量所存储的字符串中,第一次出现的word分隔符,删除字符串结尾至此分隔符处的所有字符
        • 例如:path="/var/log/yhy.txt" , echo ${path%/*} 打印结果为:/var/log
      • ${var%%word*}:其中word是指定的分隔符。功能:自右向左,查找var变量所存储的字符串中,最后一次出现的word分隔符,删除字符串结尾至此分隔符处的所有字符
        • 例如:path="/var/log/yhy.txt" , echo ${path%%/*} 打印结果为:空
    • 查找替换
      • ${var/pattern/substi}:查找var所表示的字符串,第一次被pattern所匹配到的字符串,将其替换为substi所表示的字符串
      • ${var//pattern/substi}:查找var所表示的字符串,所有被pattern所匹配到的字符串,将其所有匹配到的字符串替换为substi所表示的字符串
      • ${var/#pattern/substi}:查找var所表示的字符串,行首被pattern所匹配到的字符串,将其替换为substi所表示的字符串,如果不是行首,就不替换
      • ${var/%pattern/substi}:查找var所表示的字符串,行尾被pattern所匹配到的字符串,将其替换为substi所表示的字符串,如果不是行尾,就不替换
        -
        查找删除
      • ${var/pattern}:查找var所表示的字符串,第一次被pattern所匹配到的字符串删除
      • ${var//pattern}:查找var所表示的字符串,所有被pattern所匹配到的字符串删除
      • ${var/#pattern}:查找var所表示的字符串,行首被pattern所匹配到的字符串删除
      • ${var/%pattern}:查找var所表示的字符串,行尾被pattern所匹配到的字符串删除
    • 字符大小写转换
      • ${var^^}:把var中的所有小写转换为大写
      • ${var,,}:把var中的所有大写转换为小写
    • 变量赋值
      • ${var:-VALUE}: 如果var变量为空,或未设置那么返回VALUE,否则返回var变量的值
      • ${var:=VALUE}: 如果var变量为空,或未设置那么返回VALUE,并将VALUE赋值给var变量,否则返回var变量的值
      • ${var:+VALUE}: 如果var变量不空,那么返回VALUE
      • ${var:?ERROR_INFO}: 如果var为空,或未设置,那么返回ERROR_INFO为错误提示,否则,返回var的值
      •  
  • 综合练习1ping命令去查看192.168.10.1—192.168.10.10 范围内的所有主机是否在线,在线显示为up,不在线显示为down,分别统计在线主机,及不在线主机数量

#!/bin/bash
#
declare -i uphosts=0
declare -i downhosts=0
declare -i i=1

hostping() {
    if ping -W 1 -c 1 $1 &>/dev/null; then
        echo "$1 is up."
        let uphosts+=1
    else
        echo "$1 isdown."
        let downhosts+=1
    fi
}
while [ $i -le 67 ]; do
    hostping 172.16.$i.1
    let i++
done
echo "Up hosts: $uphosts, Down hosts: $downhosts."

  • 综合练习2:写一个脚本:能探测C类,B类,A类网络中所有的主机是否在线,以192开头的主机/bash
    #
    cping() {
        local i=1
        #
    为了看到效果,这里的255可以写成5
        while [ $i -le 5 ]; do
            if ping -W 1 -c 1 $1.$i &> /dev/null; then
                echo "$1.$i is up"
            else
                echo "$1.$i is down."
            fi
            let i++
        done
    }

    bping() {
        local j=0
        #
    为了看到效果,这里的255可以写成5
        while [ $j -le 5 ]; do
            cping $1.$j
            let j++
        done
    }
    aping() {
        local x=0
        while [ $x -le 255 ]; do
            bping $1.$x
            let x++
        done
    }
    aping 192

 

 

 

 

### 如何编写包含数组操作的 Shell 脚本 #### 定义数组 在 Linux 的 Bash 中,可以使用多种方式定义数组。最常见的方式是通过括号 `()` 来创建并初始化数组。 ```bash my_array=(value0 value1 value2) ``` 如果需要动态向数组添加元素,则可以通过如下命令: ```bash my_array+=("new_value") ``` 对于更复杂的场景,比如从 `/var/log` 目录获取 `.log` 文件名作为数组成员的情况,可以这样做[^2]: ```bash log_files=($(find /var/log -name "*.log")) ``` 这会把所有匹配到的日志文件路径存储在一个名为 `log_files` 的数组里。 #### 访问数组元素 访问单个元素时可以直接指定索引位置(注意:索引是从零开始计数),例如: ```bash echo ${log_files[0]} ``` 当想要遍历整个数组或者处理特定条件下的子集时,可以利用循环结构配合 `${array[@]}` 或者 `${!array[@]}` 变量来实现。前者表示全部元素值列表,后者则是键/索引集合。 为了计算下标为偶数项对应的日志文件总行数,在这里提供一段完整的脚本实例: ```bash #!/bin/bash # 获取 .log 结尾文件存入 log_files 数组 log_files=($(find /var/log -name "*.log")) sum_lines=0 for ((i = 0; i < ${#log_files[@]}; i++)); do if [[ $((i % 2)) -eq 0 ]]; then sum_lines=$((sum_lines + $(wc -l "${log_files[$i]}" | cut -d' ' -f1))) fi done echo "Sum of lines in even-indexed files is: $sum_lines" ``` 上述代码片段展示了如何定位符合条件的日志文件并将它们加入到数组中去;接着运用了一个简单的 `for` 循环加上模运算符 `%` 判断当前迭代次数是否满足偶数值的要求,最后累加这些选定文件各自的行数得出最终结果。 #### 函数优化性能 考虑到频繁调用外部工具可能带来的效率损失问题,现代版本的 bash 支持内置函数机制以提高执行速度。一旦声明之后,该类自定义功能就会被缓存在内存之中以便快速响应后续请求而不必每次都重新解析源码[^1]. ```bash function count_even_indexed_log_lines() { local sum_lines=0 for ((i = 0; i < ${#log_files[@]}; i++)); do if [[ $((i % 2)) -eq 0 ]]; then sum_lines=$((sum_lines + $(wc -l "${log_files[$i]}" | cut -d' ' -f1))) fi done echo "$sum_lines" } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值