zoukankan      html  css  js  c++  java
  • (八)shell编程之数组,字符串还有高级变量

    数组 array

    数组介绍

    变量:存储单个元素的内存空间
    数组:存储多个元素的连续的内存空间,相当于多个变量的集合
    数组名和索引
    索引的编号从0开始,属于数值索引
    索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash 4.0版本之后开始支持
    bash的数组支持稀疏格式(索引不连续)
    

    声明数组

    #普通数组可以不事先声明,直接使用
    declare -a ARRAY_NAME
    #关联数组必须先声明,再使用
    declare -A ARRAY_NAME
    

    注意:两者不可相互转换

    数组赋值

    数组元素的赋值
    (1) 一次只赋值一个元素

    ARRAY_NAME[INDEX]=VALUE
    

    范例:

    weekdays[0]="Sunday"
    weekdays[4]="Thursday"
    

    (2) 一次赋值全部元素

    ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)
    

    范例:

    title=("ceo" "coo" "cto")
    num=({0..10})
    alpha=({a..g})
    file=( *.sh )
    

    (3) 只赋值特定元素

    ARRAY_NAME=([0]="VAL1" [3]="VAL2" ...)
    

    (4) 交互式数组值对赋值

    read -a ARRAY
    

    范例:

    [root@centos8 ~]# declare -A course
    [root@centos8 ~]# declare -a course
    -bash: declare: course: cannot convert associative to indexed array
    [root@centos8 ~]# file=( *.sh )
    [root@centos8 ~]# declare -A file
    -bash: declare: file: cannot convert indexed to associative array
    

    范例:

    [root@ubuntu1804 ~]# i=a
    [root@ubuntu1804 ~]# j=1
    [root@ubuntu1804 ~]# declare -A arr
    [root@ubuntu1804 ~]# arr[$i$j]=long
    [root@ubuntu1804 ~]# j=2
    [root@ubuntu1804 ~]# arr[$i$j]=king
    [root@ubuntu1804 ~]# echo ${arr[*]}
    long king
    [root@ubuntu1804 ~]# echo ${arr[a1]}
    long
    [root@ubuntu1804 ~]# echo ${arr[a2]}
    king
    

    显示所有数组

    declare -a
    

    范例:

    [root@centos8 ~]# declare -a
    declare -a BASH_ARGC=()
    declare -a BASH_ARGV=()
    declare -a BASH_COMPLETION_VERSINFO=([0]="2" [1]="7")
    declare -a BASH_LINENO=()
    declare -ar BASH_REMATCH=()
    declare -a BASH_SOURCE=()
    declare -ar BASH_VERSINFO=([0]="4" [1]="4" [2]="19" [3]="1" [4]="release"
    [5]="x86_64-redhat-linux-gnu")
    declare -a DIRSTACK=()
    declare -a FUNCNAME
    declare -a GROUPS=()
    declare -a PIPESTATUS=([0]="0")
    

    引用数组

    引用特定的数组元素

    ${ARRAY_NAME[INDEX]}
    #如果省略[INDEX]表示引用下标为0的元素
    

    范例:

    [root@centos8 ~]# declare -a title=([0]="ceo" [1]="coo" [2]="cto")
    [root@centos8 ~]# echo ${title[1]}
    coo
    [root@centos8 ~]# echo ${title}
    ceo
    [root@centos8 ~]# echo ${title[2]}
    cto
    [root@centos8 ~]# echo ${title[3]}
    
    

    引用数组所有元素

    ${ARRAY_NAME[*]}
    ${ARRAY_NAME[@]}
    

    范例:

    [root@centos8 ~]# echo ${title[@]}
    ceo coo cto
    [root@centos8 ~]# echo ${title[*]}
    ceo coo cto
    

    数组的长度,即数组中元素的个数

    ${#ARRAY_NAME[*]}
    ${#ARRAY_NAME[@]}
    

    范例:

    [root@centos8 ~]# echo ${#title[*]}
    3
    

    删除数组

    删除数组中的某元素,会导致稀疏格式

    unset ARRAY[INDEX]
    

    范例:

    [root@centos8 ~]# echo ${title[*]}
    ceo coo cto
    [root@centos8 ~]# unset title[1]
    [root@centos8 ~]# echo ${title[*]}
    ceo cto
    

    删除整个数组

    unset ARRAY
    

    范例:

    [root@centos8 ~]# unset title
    [root@centos8 ~]# echo ${title[*]}
    
    

    数组数据处理

    数组切片:

    ${ARRAY[@]:offset:number}
    offset #要跳过的元素个数
    number #要取出的元素个数
    #取偏移量之后的所有元素
    {ARRAY[@]:offset}
    

    范例:

    [root@centos8 ~]# num=({0..10})
    [root@centos8 ~]# echo ${num[*]:2:3}
    2 3 4
    [root@centos8 ~]# echo ${num[*]:6}
    6 7 8 9 10
    

    向数组中追加元素:

    ARRAY[${#ARRAY[*]}]=value
    ARRAY[${#ARRAY[@]}]=value
    

    范例:

    [root@centos8 ~]# num[${#num[@]}]=11
    [root@centos8 ~]# echo ${#num[@]}
    12
    [root@centos8 ~]# echo ${num[@]}
    0 1 2 3 4 5 6 7 8 9 10 11
    

    关联数组

    declare -A ARRAY_NAME
    ARRAY_NAME=([idx_name1]='val1' [idx_name2]='val2‘...)
    

    注意:关联数组必须先声明再调用

    范例

    [root@centos8 ~]# name[ceo]=long
    [root@centos8 ~]# name[cto]=wang
    [root@centos8 ~]# name[coo]=zhang
    [root@centos8 ~]# echo ${name[ceo]}
    zhang
    [root@centos8 ~]# echo ${name[cto]}
    zhang
    [root@centos8 ~]# echo ${name[coo]}
    zhang
    [root@centos8 ~]# echo ${name}
    zhang
    [root@centos8 ~]# declare -A name
    -bash: declare: name: cannot convert indexed to associative array
    [root@centos8 ~]# unset name
    [root@centos8 ~]# declare -A name
    [root@centos8 ~]# name[ceo]=long
    [root@centos8 ~]# name[cto]=wang
    [root@centos8 ~]# name[coo]=zhang
    [root@centos8 ~]# echo ${name[coo]}
    zhang
    [root@centos8 ~]# echo ${name[ceo]}
    long
    [root@centos8 ~]# echo ${name[cto]}
    wang
    [root@centos8 ~]# echo ${name[*]}
    long wang zhang
    

    范例:关联数组

    [root@centos8 ~]# declare -A student
    [root@centos8 ~]# student[name1]=lijun
    [root@centos8 ~]# student[name2]=ziqing
    [root@centos8 ~]# student[age1]=18
    [root@centos8 ~]# student[age2]=16
    [root@centos8 ~]# student[gender1]=m
    [root@centos8 ~]# student[city1]=nanjing
    [root@centos8 ~]# student[gender2]=f
    [root@centos8 ~]# student[city2]=anhui
    [root@centos8 ~]# student[gender2]=m
    [root@centos8 ~]# student[name50]=alice
    [root@centos8 ~]# student[name3]=tom
    [root@centos8 ~]# for i in {1..50};do echo student[name$i]=${student[name$i]};done
    

    范例:编写脚本,定义一个数组,数组中的元素对应的值是/var/log目录下所有以.log结尾的文件;统计出其下标为偶数的文件中的行数之和

    #!/bin/bash
    #
    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: $lines"
    

    字符串处理

    基于偏移量取字符串

    #返回字符串变量var的字符的长度,一个汉字算一个字符
    ${#var}
    #返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,到最后的部分,
    offset的取值在0 到 ${#var}-1 之间(bash4.2后,允许为负值)
    ${var:offset}
    #返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,长度为number的部分
    ${var:offset:number}
    #取字符串的最右侧几个字符,取字符串的最右侧几个字符, 注意:冒号后必须有一空白字符
    ${var: -length}
    #从最左侧跳过offset字符,一直向右取到距离最右侧lengh个字符之前的内容,即:掐头去尾
    ${var:offset:-length}
    #先从最右侧向左取到length个字符开始,再向右取到距离最右侧offset个字符之间的内容,注意:-
    length前空格,并且length必须大于offset
    ${var: -length:-offset}
    

    范例:

    [root@centos8 script40]# str=abcdef我你他
    [root@centos8 script40]# echo ${#str}
    9
    [root@centos8 script40]# echo ${str:2}
    cdef我你他
    [root@centos8 script40]# echo ${str:2:3}
    cde
    [root@centos8 script40]# echo ${str:-3}
    abcdef我你他
    [root@centos8 script40]# echo ${str: -3}
    我你他
    [root@centos8 script40]# echo ${str:2:-3}
    cdef
    [root@centos8 script40]# echo ${str: -2:-3}
    -bash: -3: substring expression < 0
    [root@centos8 script40]# echo ${str: -3:-2}
    我
    [root@centos8 script40]# echo ${str:-3:-2}
    abcdef我你他
    [root@centos8 script40]# echo ${str: -3:-2}
    我
    [root@centos8 script40]# echo ${str: -5:-2}
    ef我
    

    基于模式取子串

    #其中word可以是指定的任意字符,自左而右,查找var变量所存储的字符串中,第一次出现的word, 删除字
    符串开头至第一次出现word字符串(含)之间的所有字符,即懒惰模式,以第一个word为界删左留右
    ${var#*word}
    #同上,贪婪模式,不同的是,删除的是字符串开头至最后一次由word指定的字符之间的所有内容,即贪婪模
    式,以最后一个word为界删左留右
    ${var##*word}
    

    范例:

    [root@centos8 ~]# file="var/log/messages"
    [root@centos8 ~]# echo ${file#*/}
    log/messages
    [root@centos8 ~]# echo ${file##*/}
    messages
    
    #其中word可以是指定的任意字符,功能:自右而左,查找var变量所存储的字符串中,第一次出现的word,
    删除字符串最后一个字符向左至第一次出现word字符串(含)之间的所有字符,即懒惰模式,以从右向左的第
    一个word为界删右留左
    ${var%word*}
    #同上,只不过删除字符串最右侧的字符向左至最后一次出现word字符之间的所有字符,即贪婪模式,以从右向
    左的最后一个word为界删右留左
    ${var%%word*}
    

    范例:

    [root@centos8 ~]# file="var/log/messages"
    [root@centos8 ~]# echo ${file%/*}
    var/log
    [root@centos8 ~]# echo ${file%%/*}
    var
    

    范例:

    [root@centos8 ~]# url=http://www.longxuan.com:8080
    [root@centos8 ~]# echo ${url##*:}
    8080
    [root@centos8 ~]# echo ${url%%:*}
    http
    

    查找替换

    #查找var所表示的字符串中,第一次被pattern所匹配到的字符串,以substr替换之
    ${var/pattern/substr}
    #查找var所表示的字符串中,所有能被pattern所匹配到的字符串,以substr替换之
    ${var//pattern/substr}
    #查找var所表示的字符串中,行首被pattern所匹配到的字符串,以substr替换之
    ${var/#pattern/substr}
    #查找var所表示的字符串中,行尾被pattern所匹配到的字符串,以substr替换之
    ${var/%pattern/substr}
    

    查找并删除

    #删除var表示的字符串中第一次被pattern匹配到的字符串
    ${var/pattern}
    删除var表示的字符串中所有被pattern匹配到的字符串
    ${var//pattern}
    删除var表示的字符串中所有以pattern为行首匹配到的字符串
    ${var/#pattern}
    删除var所表示的字符串中所有以pattern为行尾所匹配到的字符串
    ${var/%pattern}
    

    字符大小写转换

    #把var中的所有小写字母转换为大写
    ${var^^}
    #把var中的所有大写字母转换为小写
    ${var,,}
    

    高级变量

    范例:

    [root@centos8 ~]# title=ceo
    [root@centos8 ~]# name=${title-long}
    [root@centos8 ~]# echo $name
    ceo
    [root@centos8 ~]# title=
    [root@centos8 ~]# name=${title-long}
    [root@centos8 ~]# echo $name
    [root@centos8 ~]# unset title
    [root@centos8 ~]# name=${title-long}
    [root@centos8 ~]# echo $name
    long
    

    范例:

    [root@centos8 ~]# title=ceo
    [root@centos8 ~]# name=${title:-long}
    [root@centos8 ~]# echo $name
    ceo
    [root@centos8 ~]# title=
    [root@centos8 ~]# name=${title:-long}
    [root@centos8 ~]# echo $name
    long
    [root@centos8 ~]# unset title
    [root@centos8 ~]# name=${title:-long}
    [root@centos8 ~]# echo $name
    long
    

    高级变量用法-有类型变量

    Shell变量一般是无类型的,但是bash Shell提供了declare和typeset两个命令用于指定变量的类型,两
    个命令是等价的

    declare [选项] 变量名
    选项:
    -r 声明或显示只读变量
    -i 将变量定义为整型数
    -a 将变量定义为数组
    -A 将变量定义为关联数组
    -f 显示已定义的所有函数名及其内容
    -F 仅显示已定义的所有函数名
    -x 声明或显示环境变量和函数,相当于export
    -l 声明变量为小写字母 declare -l var=UPPER
    -u 声明变量为大写字母 declare -u var=lower
    -n make NAME a reference to the variable named by its value
    

    变量间接引用

    eval命令

    eval命令将会首先扫描命令行进行所有的置换,然后再执行该命令。该命令适用于那些一次扫描无法实
    现其功能的变量,该命令对变量进行两次扫描
    范例:

    [root@centos8 ~]# CMD=whoami
    [root@centos8 ~]# echo $CMD
    whoami
    [root@centos8 ~]# eval $CMD
    root
    [root@centos8 ~]# n=10
    [root@centos8 ~]# echo {0..$n}
    {0..10}
    [root@centos8 ~]# eval echo {0..$n}
    0 1 2 3 4 5 6 7 8 9 10
    [root@centos8 ~]# for i in `eval echo {1..$n}` ;do echo i=$i ;done
    i=1
    i=2
    i=3
    i=4
    i=5
    i=6
    i=7
    i=8
    i=9
    i=10
    
    [root@centos8 ~]# i=a
    [root@centos8 ~]# j=1
    [root@centos8 ~]# $i$j=hello
    -bash: a1=hello: command not found
    [root@centos8 ~]# eval $i$j=hello
    [root@centos8 ~]# echo $i$j
    a1
    [root@centos8 ~]# echo $a1
    hello
    

    间接变量引用

    如果第一个变量的值是第二个变量的名字,从第一个变量引用第二个变量的值就称为间接变量引用
    variable1的值是variable2,而variable2又是变量名,variable2的值为value,间接变量引用是指通过
    variable1获得变量值value的行为

    variable1=variable2
    variable2=value
    #示例:
    i=1
    $1=wang
    

    bash Shell提供了两种格式实现间接变量引用

    #方法1
    #变量赋值
    eval tempvar=$$variable1
    #显示值
    eval echo $$variable1
    eval echo '$'$variable1
    #方法2
    #变量赋值
    tempvar=${!variable1}
    #显示值
    echo ${!variable1}
    

    范例:

    [root@centos8 ~]# ceo=name
    [root@centos8 ~]# name=long
    [root@centos8 ~]# echo $ceo
    name
    [root@centos8 ~]# echo $$ceo
    33722ceo
    [root@centos8 ~]# echo $$
    33722
    [root@centos8 ~]# echo $$ceo
    $name
    [root@centos8 ~]# eval echo $$ceo
    long
    [root@centos8 ~]# eval tmp=$$ceo
    [root@centos8 ~]# echo $tmp
    long
    [root@centos8 ~]# echo ${!ceo}
    long
    

    范例:

    [root@server ~]# N1=N2
    [root@server ~]# N2=longwang
    [root@server ~]# eval NAME=$$N1
    [root@server ~]# echo $NAME
    longwang
    [root@server ~]# NAME=${!N1}
    [root@server ~]# echo $NAME
    longwang
    

    范例: 批量创建用户

    #!/bin/bash
    n=$#
    [ $n -eq 0 ] && { echo "Usage: `basename $0` username..." ; exit 2; }
    for i in `eval echo {1..$n}`;do
      user=${!i}
      id $user &> /dev/null && echo $user is exist || { useradd $user; echo $user
    is created; }
    done
    
    [root@centos8 ~]# bash create_user.sh hehe xixi haha
    hehe is created
    xixi is created
    haha is created
    

    变量引用 reference

    [root@centos8 ~]#cat test.sh
    #!/bin/bash
    title=ceo
    ceo=long
    #声明引用变量ref
    declare -n ref=$title
    [ -R ref ] && echo "reference" # [ -R var ] 是bash4.4新特性
    echo ref=$ref
    ceo=king
    echo ref=$ref
    [root@centos8 ~]# bash test.sh
    reference
    ref=long
    ref=king
    
  • 相关阅读:
    Qt 学习之路 :自定义只读模型
    Qt 学习之路:QSortFilterProxyModel
    Qt 学习之路 :可视化显示数据库数据
    Qt 学习之路 :访问网络(4)
    Qt 学习之路:QFileSystemModel
    高级Bash脚本编程指南
    CGI
    shell学习
    【shell】while read line 与for循环的区别
    管道技巧-while read line
  • 原文地址:https://www.cnblogs.com/xuanlv-0413/p/14881446.html
Copyright © 2011-2022 走看看