shell脚本中数组的用法

2021/9/4 21:38:15
栏目: 其他类
开发者测试专用服务器限时活动,0元免费领,库存有限,领完即止! 点击查看>>

本篇内容介绍了“shell脚本中数组的用法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

问题描述:某个员工的linux系统有大量重复的软件(版本不同),导致使用yum安装软件时报错。现在需要将重复的软件找出来,将低版本的软件删掉。执行rpm -qa | sort 显示如下:

[root@cws85 ~]# rpm -qa | sort a52dec-0.7.4-27.el7.x86_64
aalib-libs-1.4.0-0.22.rc5.el7.x86_64
abattis-cantarell-fonts-0.0.25-1.el7.noarch
abrt-2.1.11-52.el7.centos.x86_64
abrt-addon-ccpp-2.1.11-52.el7.centos.x86_64
abrt-addon-kerneloops-2.1.11-52.el7.centos.x86_64
abrt-addon-pstoreoops-2.1.11-52.el7.centos.x86_64
abrt-addon-python-2.1.11-52.el7.centos.x86_64
abrt-addon-vmcore-2.1.11-52.el7.centos.x86_64
abrt-addon-xorg-2.1.11-52.el7.centos.x86_64
abrt-cli-2.1.11-52.el7.centos.x86_64
abrt-console-notification-2.1.11-52.el7.centos.x86_64
abrt-dbus-2.1.11-52.el7.centos.x86_64
abrt-desktop-2.1.11-52.el7.centos.x86_64
abrt-gui-2.1.11-52.el7.centos.x86_64
abrt-gui-libs-2.1.11-52.el7.centos.x86_64
abrt-java-connector-1.0.6-12.el7.x86_64
abrt-libs-2.1.11-52.el7.centos.x86_64
abrt-python-2.1.11-52.el7.centos.x86_64
abrt-retrace-client-2.1.11-52.el7.centos.x86_64
abrt-tui-2.1.11-52.el7.centos.x86_64
accountsservice-0.6.50-4.el7.1.x86_64
accountsservice-libs-0.6.50-4.el7.1.x86_64
acl-2.2.51-14.el7.x86_64
adcli-0.8.1-6.el7_6.1.x86_64
adwaita-cursor-theme-3.28.0-1.el7.noarch
adwaita-gtk2-theme-3.28-2.el7.x86_64
adwaita-icon-theme-3.28.0-1.el7.noarch
adwaita-qt5-1.0-1.el7.x86_64
aic94xx-firmware-30-6.el7.noarch
alsa-firmware-1.0.28-2.el7.noarch
alsa-lib-1.1.6-2.el7.x86_64
alsa-plugins-pulseaudio-1.1.6-1.el7.x86_64
alsa-tools-firmware-1.1.0-1.el7.x86_64
alsa-utils-1.1.6-1.el7.x86_64
anaconda-core-21.48.22.121-1.el7.centos.x86_64
anaconda-core-21.48.22.147-1.el7.centos.0.1.x86_64
anaconda-gui-21.48.22.147-1.el7.centos.0.1.x86_64
anaconda-tui-21.48.22.121-1.el7.centos.x86_64                 #这是重复软件的低版本anaconda-tui-21.48.22.147-1.el7.centos.x86_64          #这是重复软件的高版本anaconda-widgets-21.48.22.147-1.el7.centos.0.1.x86_64
..........省略
总共2586个软件

要求:如上所示,需要将低版本的软件删除,如下是例外:

[root@cws85 ~]# rpm -qa | grep audit-libs-[0-9]  
audit-libs-2.8.4-4.el7.i686
audit-libs-2.8.4-4.el7.x86_64
虽然是重复软件,但一个是x86_64,一个是i686,这样不能删除,只能删除重复的_x86_64结尾的软件

数组:脚本中用到了数组,下面是数组的部分内容概述:

1.数组定义:
declare -a  数组名    #定义索引数组,下标从0开始
declare -A 数组名    #定义关联数组,下标为任意字符

2.数组赋值与复制:
2.1.可以通过命令替换的方式给数组赋值: declare -a SOFT1=($(rpm -qa | sort))  #数组SOFT1保存着所有软件
2.2.数组复制操作:linux2=(${linux1[@]}) #数组linux2复制了数组linux1的内容

3.数组的字符串操作:
3.1.字符串的操作符可以用在数组上,如:${#string} 用于数组 ${#array[@]},等等等等。
3.2.数组遍历: for i in ${!SOFT[@]}  #注意加上感叹号可以遍历数组中的值,假设SOFT的下标最大是2586,通过for循环可以遍历完数组,i的值从0依次到2586。

脚本内容:

#!/bin/bashdeclare -a SOFT1=($(rpm -qa | sort))      #数组SOFT1保存所有软件名称for i in ${!SOFT1[*]}                 #遍历数组SOFT1 do   declare -a SOFT2[$i]=${SOFT1[$i]%%-[0-9]*}        #数组SOFT2复制数组SOFT1的部分内容,%%是字符串截取符号,相当于去掉软件的版本号,只保留软件名称 donefor i in $(seq 0 $((${#SOFT2[@]}-1)))        #遍历数组SOFT2  do     let "j=$i+5"  
     for (( ;i<j;j--))            #i小于j时跳出循环,循环执行5次       do         if [ "${SOFT2[$i]}" == "${SOFT2[$j]}" ]     #测试是否有重复软件           then              declare -a SOFT3=($(rpm -qa | grep "^${SOFT2[$i]}-[0-9]" | sort))    #如果软件有重复,执行rpm -qa | grep 重复软件名,赋值给数组SOFT3              if (( "${#SOFT3[@]}" < 2 ))     #检测数组SOFT3的下标个数是否小于2(多加一层保险)                then                   echo "${SOFT2[$i]} no repeat version" >>/tmp/soft  && continue    #小于2输出该软件没有重复的版本              elif (( "${#SOFT3[@]}" > 2 ))     #如果下标大于2,也就是(rpm -qa | grep 重复软件)有多于2个软件                then                   X86=0 I686=0           #初始化两个变量,用于后面比较                   for i in ${!SOFT3[*]}      #遍历数组SOFT3                     do                       [[ "${SOFT3[$i]##*.}" == "i686" ]] && I686=$((I686+1)) || X86=$((X86+1))     #如果软件名结尾是i686,那么变量I686加1,否则X86加1                     done                       (( "$X86" >= "$I686" )) && echo "${SOFT3[0]} can1 delete" >>/tmp/soft      #如果X86值大于I686,输出软件能够删除               elif (( "${#SOFT3[@]}" == 2 ))         #如果下标等于2,也就是(rpm -qa | grep 重复软件)有两个                then                   [[ "${SOFT3[0]##*.}" == "i686" || "${SOFT3[1]##*.}" == "i686" ]] && { echo "${SOFT3[0]} only two packages but has I686" >>/tmp/soft ; continue ; }          #两个软件里只要有1个是i686结尾的,输出不能删除                   echo "${SOFT3[0]} can2 delete" >>/tmp/soft
             fi         fi     done  done

脚本说明

1.数组SOFT1保存所有软件的完整名称,数组SOFT2是通过数组复制加上字符串的替换,截取出不带版本名称的软件名,比如 SOFT1[4]=abrt-addon-ccpp-2.1.11-52.el7.centos.x86_64,  SOFT2[4]=abrt-addon-ccpp。

2.利用for循环遍历数组SOFT2来检测那些是重复软件,如下:

for i in $(seq 0 $((${#SOFT2[@]}-1)))       #遍历数组SOFT2do    
     let  "j=$i+5"       #j比i大5,用于测试某个软件名与它后面的5个软件名是否相等,因为是通过rpm -qa | sort排序过,所以软件名都是按照字母顺序排的,比较5个就可以了。       for (( ;i<j;j--))        
         do             if [ "${SOFT2[$i]}" == "${SOFT2[$j]}" ]         #比较是否有重复软件名

3.如果有重复,需要处理软件后缀名的问题,只有重复的以X86结尾的软件名才输出该软件可以删除。利用数组SOFT3=($(rpm -qa | grep "^${SOFT2[$i]}-[0-9]" | sort)) 来保存搜索出的重复软件,然后在进行判断比较

脚本输出结果:输出被重定向到文件里,文件内容如下:

anaconda-core-21.48.22.121-1.el7.centos.x86_64 can2 deleteanaconda-tui-21.48.22.121-1.el7.centos.x86_64 can2 deleteaudit-libs-2.8.4-4.el7.i686 only two packages but has I686avahi-libs-0.6.31-17.el7.x86_64 can2 deletebzip2-libs-1.0.6-13.el7.i686 only two packages but has I686copy-jdk-configs-2.2-5.el7_4.noarch can2 deletecracklib-2.9.0-11.el7.i686 only two packages but has I686cryptsetup-libs-1.7.4-3.el7_4.1.x86_64 can2 deletedbus-1.10.24-13.el7_6.x86_64 can2 deletedbus-libs-1.10.24-13.el7_6.x86_64 can2 deletedevice-mapper-event-libs-1.02.149-10.el7_6.3.x86_64 can2 deleteelfutils-libelf-0.172-2.el7.i686 only two packages but has I686elfutils-libs-0.172-2.el7.i686 only two packages but has I686fprintd-0.5.0-4.0.el7_0.x86_64 can2 deletefreetype-2.8-12.el7_6.1.i686 only two packages but has I686glib2-2.54.2-2.el7.x86_64 can2 deleteglibc-2.17-260.el7_6.6.i686 only two packages but has I686........省略
总共81行,能删除的有52行(有少数错误,后面说明)

脚本调试信息:sh -x 脚本名显示的部分内容如下:

+ SOFT1=($(rpm -qa | sort))      #数组SOFT1保存完整软件名++ rpm -qa
++ sort
+ declare -a SOFT1
+ for i in '${!SOFT1[*]}'                #遍历数组SOFT1 + declare -a 'SOFT2[0]=a52dec'      #给数组SOFT2赋值,只保留软件名+ for i in '${!SOFT1[*]}'+ declare -a 'SOFT2[1]=aalib-libs'+ for i in '${!SOFT1[*]}'+ declare -a 'SOFT2[2]=abattis-cantarell-fonts'+ for i in '${!SOFT1[*]}'+ declare -a 'SOFT2[3]=abrt'+ for i in '${!SOFT1[*]}'+ declare -a 'SOFT2[4]=abrt-addon-ccpp'+ ..............省略,总共2586个

++ seq 0 2585   
+ for i in '$(seq 0 $((${#SOFT2[@]}-1)))'          #遍历数组SOFT2,测试哪些是重复软件+ let j=0+5       #总共比较5次+ (( 1 ))
+ (( i<j ))
+ '[' a52dec == abrt-addon-kerneloops ']'+ (( j-- ))+ (( i<j ))
+ '[' a52dec == abrt-addon-ccpp ']'+ (( j-- ))+ (( i<j ))
+ '[' a52dec == abrt ']'+ (( j-- ))+ (( i<j ))
+ '[' a52dec == abattis-cantarell-fonts ']'+ (( j-- ))+ (( i<j ))
+ '[' a52dec == aalib-libs ']'                             #a53dec...不是一个重复软件+ (( j-- ))+ (( i<j ))
+ for i in '$(seq 0 $((${#SOFT2[@]}-1)))'     #比较下一个,数组下标加1+ let j=1+5...........................................................................省略
+ for i in '$(seq 0 $((${#SOFT2[@]}-1)))'+ let j=35+5             #数组下标到35+ (( 1 ))
+ (( i<j ))
+ '[' anaconda-core == anaconda-widgets ']'+ (( j-- ))+ (( i<j ))
+ '[' anaconda-core == anaconda-tui ']'+ (( j-- ))+ (( i<j ))
+ '[' anaconda-core == anaconda-tui ']'+ (( j-- ))+ (( i<j ))
+ '[' anaconda-core == anaconda-gui ']'+ (( j-- ))+ (( i<j ))
+ '[' anaconda-core == anaconda-core ']'                                 #这里找到重复软件+ SOFT3=($(rpm -qa | grep "^${SOFT2[$i]}-[0-9]" | sort))     #数组SOFT3赋值=(rpm -qa |grep ^anaconda-core-[0-9]|sort)++ rpm -qa
++ sort++ grep '^anaconda-core-[0-9]'+ declare -a SOFT3
+ ((  2 < 2  ))
+ ((  2 > 2  ))
+ ((  2 == 2  ))      #刚好有两个包+ [[ x86_64 == i686 ]]     #第一个包后缀是x86_64+ [[ x86_64 == i686 ]]    #第二个包后缀是x86_64+ echo 'anaconda-core-21.48.22.121-1.el7.centos.x86_64 can2 delete'      #输出能删除+ ..........................省略

脚本输出错误:脚本输出文件里总共有52行是能删除的软件,其中有几个是错误的,由于软件名称导致的错误,如下:

错误1: 软件名称: 字符-数字-字符-版本号  导致判断错误
java-1.8.0-openjdk-1.8.0.222.b10-0.el7_6.x86_64 can1 delete
java-1.8.0-openjdk-1.8.0.222.b10-0.el7_6.x86_64 can1 delete
SOFT2[$i]=${SOFT1[$i]%%-[0-9]*}  #问题就在截取软件名称上,SOFT2=java, 正确的应该是SOFT2=java-1.8.0-openjdk。

错误2:错误的软件名称结尾,该软件没有以.X86或其他结尾
gpg-pubkey-0c1289c0-58c6ad7d can1 delete
gpg-pubkey-0c1289c0-58c6ad7d can1 delete
gpg-pubkey-0c1289c0-58c6ad7d can1 delete
在给SOFT1赋值的时候需要过滤掉这种没有以.X86或其他后缀结尾的软件

总结:很少在脚本中用到数组,通过这个脚本加深了对数组的掌握与应用。不知道怎么解决脚本输出中的错误1这种问题,大部分的软件都能正确去掉版本号,个别的软件名就不行,感觉总会有漏洞。该脚本主要在于练习数组的应用,同时也能从二千多个软件里面找出重复软件,虽然有个别错误,但也会比用眼睛找重复软件好,对照着输出文件来删除软件会轻松很多。

“shell脚本中数组的用法”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注辰迅云网站,小编将为大家输出更多高质量的实用文章!


辰迅云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>

推荐阅读: 虚拟主机渗透测试的方法是什么