shell脚本练习--数组

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

[[email protected] ~]# 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个软件

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

[[email protected] ~]# 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/bash
declare -a SOFT1=($(rpm -qa | sort))      #数组SOFT1保存所有软件名称

for i in ${!SOFT1[*]}                 #遍历数组SOFT1
 do
   declare -a SOFT2[$i]=${SOFT1[$i]%%-[0-9]*}        #数组SOFT2复制数组SOFT1的部分内容,%%是字符串截取符号,相当于去掉软件的版本号,只保留软件名称
 done

for 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)))       #遍历数组SOFT2
do
     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 delete
anaconda-tui-21.48.22.121-1.el7.centos.x86_64 can2 delete
audit-libs-2.8.4-4.el7.i686 only two packages but has I686
avahi-libs-0.6.31-17.el7.x86_64 can2 delete
bzip2-libs-1.0.6-13.el7.i686 only two packages but has I686
copy-jdk-configs-2.2-5.el7_4.noarch can2 delete
cracklib-2.9.0-11.el7.i686 only two packages but has I686
cryptsetup-libs-1.7.4-3.el7_4.1.x86_64 can2 delete
dbus-1.10.24-13.el7_6.x86_64 can2 delete
dbus-libs-1.10.24-13.el7_6.x86_64 can2 delete
device-mapper-event-libs-1.02.149-10.el7_6.3.x86_64 can2 delete
elfutils-libelf-0.172-2.el7.i686 only two packages but has I686
elfutils-libs-0.172-2.el7.i686 only two packages but has I686
fprintd-0.5.0-4.0.el7_0.x86_64 can2 delete
freetype-2.8-12.el7_6.1.i686 only two packages but has I686
glib2-2.54.2-2.el7.x86_64 can2 delete
glibc-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这种问题,大部分的软件都能正确去掉版本号,个别的软件名就不行,感觉总会有漏洞。该脚本主要在于练习数组的应用,同时也能从二千多个软件里面找出重复软件,虽然有个别错误,但也会比用眼睛找重复软件好,对照着输出文件来删除软件会轻松很多。

原文地址:https://blog.51cto.com/pkimin3/2437158

时间: 2024-10-13 12:08:54

shell脚本练习--数组的相关文章

Linux中的shell脚本编程——数组 ,高级字符串操作 ,高级变量 ,配置用户环境

概述: 概述: 本章节将讲述Linux中shell脚本编程的数组,高级字符串处理,高级变量和配置用户的环境. 一.函数和位置参数扩展 1.shift 命令实现在位置参数中的跳跃,会把最左边的参数挤掉     2.匿名函数的使用 第一篇:数组 一.数组的定义: 1.变量:存储单个元素的内存空间 2.数组:存储多个元素的连续的内存空间,相当于多个变量的集合. 3.数组名和索引 索引:编号从0开始,属于数值索引 注意:索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash4.0版本之后开

shell 脚本-关联数组

shell 的关联数组 Shell Associative Array   bashi没有原生的对于类似hash table的支持,不像perl或python.下标数组元素是通过数组下标(数组下标可以是算术表达式,其结果必须是一个整数)来访问的,但是这种访问方式在表达某些关联性很强的数据时会存在限制.shell 提供了另外一种数组,其可以使用任意的字符串作为下标(不必是整数)来访问数组元素.这种数组叫做关联数组(associative array).关联数组的下标和值称为键值对,它们是一一对应的

shell 脚本之数组 和 yum 【下】

数组 变量:存储单个元素的内存空间 数组:存储多个元素的连续的内存空间,相当于多个变量的 集合. 数组名和索引 索引:编号从0开始,属于数值索引 注意:索引可支持使用自定义的格式,而不仅是数值格式 ,即为关联索引,bash4.0版本之后开始支持. bash的数组支持稀疏格式(索引不连续) 声明数组: declare -a ARRAY_NAME declare -A ARRAY_NAME: 关联数组 数组赋值 数组元素的赋值: (1) 一次只赋值一个元素: ARRAY_NAME[INDEX]=VA

18 shell脚本--009数组与字符串

回顾: 函数:写一个代码块,用来重复调用的: 1.函数的写法格式 2.参数,在函数名后面直接加,即可:如果在外面 abc(){ 函数体 [email protected] } abc 1 2 3 4 5 :wq a.sh 1 2 3 4 5 6 3.变量 local本地变量 local i=1 如果在函数体外同样也定义了一个相同的变量 扩展:source / bash / chmod+x 全路径 [父子进程的问题] 4.return 结束函数体的执行 和exit 的却别 return 和 exi

shell脚本之数组

数组:    一堆变量的集合. 声明:        declare -a ARRAYNNAME        其中每个变量为ARRAYNAME[INDEX]        INDEX从0开始. 赋值:        ARRAYNAME[INDEX] = VALUE        ARRAYNAME = (VALUE1 VALUE2 ...)        ARRAYNAME = ( [INDEX1]=VALUE1 [INDEX2]=VALUE2 ...) 特殊引用方法:        ${#A

Shell脚本(五)数组

平时写脚本还没有用到过数组,暂时先记录下用法. #!/bin/bash array1=(1 2 3 4 5) array1_length=${#array1[@]} echo "array1 length: ${array1_length}" for item in ${array1[@]} do echo "current item of array1: ${item}" done array2[0]="test0" array2[1]=&qu

shell脚本编程数组

数组: 变量:存储单个元素的内存空间 数组:存储多个元素的连续的内存空间,相当于多个变量的集合 数组名和索引 索引:编号从0开始,属于数值索引 注意:索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引, bash4.0版本之后开始支持 bash的数组支持稀疏格式(索引不连续) 声明数组: declare -a ARRAY_NAME:普通数组(声明可有可无) declare -A ARRAY_NAME: 关联数组(必须先声明才可用) 注意:两者不可相互转换 数组赋值 单个赋值:weekda

shell脚本基础--数组

q1.数组 我们知道,变量就是内存里的存储空间,每个变量只可以存储一个数据,进行一次性的赋值操作,那么遇到一些需要连续存储并读取的任务时,如果还是依靠变量进行多次存储,既不会保证内存空间的连续性,也大大降低了CPU的效率,这时就需要数组这一类型的变量出马了! 数组变量: 数组简单来说就是存放一个或多个元素的连续的内存空间,相当于多个变量的集合: 数组的索引有以下方式: 1.数字索引.称为索引数组 Index ARRAY: 0,1,2,3.... 2.名称(字符串): 称为关联数组 Related

Shell脚本编程——数组(array)

数组与变量的区别 变量:存储单个元素的内存空间 数组:存储多个元素的连续的内存空间,相当于多个变量的集合 数组=数组名+索引 索引:编号从0开始,属于数值索引 注意:索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash4.0版本之后开始支持    bash的数组支持稀疏格式(索引不连续) 定义数组 declare -a ARRAY_NAME:普通数组 declare -A ARRAY_NAME: 关联数组  数组元素的赋值:  (1) 一次只赋值一个元素:   ARRAY_NAM