note_17.1_shell数组、bash字符串操作

shell脚本编程

变量:存储单个元素的内存空间;
数组:存储多个元素的连续的内存空间;
├── 数组名:整个数组只有一个名字;
└── 数组索引:编号从0开始;

数组名[索引],
${ARRAY_NAME[INDEX]}

数组引用必须要加上花括号

注意:bash-4及之后的版本,支持自定义索引格式,而不仅仅是0,1,2,...数字格式;
此类数组称之为“关联数组”

声明数组:

├── declare -a NAME:声明索引数组;
└── declare -A NAME:声明关联数组;(可以理解成key-value)

数组中元素的赋值方式:

  1. 一次只赋值一个元素;
    ARRAY_NAME[INDEX]=value
  2. 一次赋值全部元素;
    ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)
  3. 只赋值特定元素;
    ARRAY_NAME=([0]="VAL1" [3]="VAL4" ...)

    注意:bash支持稀疏格式的数组;

  4. read -a ARRAY_NAME

数组的长度(数组中元素的个数):

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

${#ARRAY_NAME}数组第一个元素的字符数

示例:生成10个随机数,并找出其中的最大值和最小值;

[root@localhost ~]# bash /scripts/e17-1-1.sh
13621 26112 6628 32725 6633 10439 12141 11041 17213 4454
max number is : 32725
[root@localhost ~]# cat /scripts/e17-1-1.sh
#!/bin/bash

declare -a rand
declare -i max=0
for i in {1..10};do
    rand[$[$i-1]]=$RANDOM
    [ ${rand[$[$i-1]]} -gt $max ] && max=${rand[$[$i-1]]}
done
echo ${rand[*]}
echo "max number is : $max"

练习:生成10个随机数,而后由小到大进行排序;

[root@localhost ~]# bash  /scripts/e17-1-2.sh
32513 24837 22630 21323 17125 15063 7133 611 567 124
[root@localhost ~]# bash  /scripts/e17-1-2.sh
30149 28684 26592 24703 19941 18643 16756 11298 7533 2952
[root@localhost ~]# cat  /scripts/e17-1-2.sh
#!/bin/bash

declare -a sortarr
tmp=0
foo=0
bar=0
for i in {0..9};do
    sortarr[$i]=$RANDOM
done
for ((i=0 ; i<10 ; i++));do
    foo=$i
    for (( j=$[$i-1] ; j>=0 ; j-- ));do
        bar=$j
        if [ ${sortarr[$foo]} -gt ${sortarr[$bar]} ];then
            tmp=${sortarr[$foo]}
            sortarr[$foo]=${sortarr[$bar]}
            sortarr[$bar]=$tmp
            foo=$bar
        fi
    done
done
echo ${sortarr[*]}

练习:写一个脚本

定义一个数组,数组中的元素是/var/log目录下所有以.log结尾的文件;统计其下标为偶数的文件中的行数之和;

[root@localhost ~]# bash /scripts/e17-1-3.sh
579
[root@localhost ~]# cat /scripts/e17-1-3.sh
#!/bin/bash

declare -a files
files=(/var/log/*.log)
declare -i  sum=0
for i in $(seq 0 $[${#files[*]}-1]);do
    [ $[$i%2] -eq 0 ] && let sum+=`wc -l ${files[$i]} | cut -d' ' -f1`
done
echo $sum

引用数组中的所有元素:

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

数组元素切片:

${ARRAY_NAME[@]:offset:number}
├── offset:要路过的元素个数;
└── number:要取出的元素个数;省略number时,表示取偏移量之后的所有元素;

  • 向非稀疏格式数组中追加元素:
    ARRAY_NAME[${#ARRAY_NAME[*]}]=

  • 删除数组中的某元素:
    unset ARRAY[INDEX]

关联数组:

declare -A ARRAY_NAME
ARRAY_NAME=([index_name1]="value1" [index_name2]="value2" ...)


bash的内置字符串处理工具:

字符串切片:
${var:offset:number}

取字符串的最右侧的几个字符:${var: -length}
注意:冒号后必须有一个空白字符

  • 基于模式取子串:
    ${var#*word}:其中word是指定的分隔符;功能:自左而右,查找var变量所存储的字符串中,第一次出现的word分隔符,删除字符串开头至此分隔符之间的所有字符;

    [root@localhost ~]# str='hello world 123'
    [root@localhost ~]# echo ${str#*world}
    123
    

    ${var##*word}:其中word是指定的分隔符;功能:自左而右,查找var变量所存储的字符串中,最后一次出现的word分隔符,删除字符串开头至此分隔符之间的所有字符;

    mypath="/etc/init.d/functions"
    ${mypath##*/}:   functions
    ${mypath#*/}:  etc/init.d/functions
    

    ${var%word*}:其中word是指定的分隔符;功能:自右而左,查找var变量所存储的字符串中,第一次出现的word分隔符,删除此分隔符至字符串尾部之间的所有字符;
    ${var%%word*}:其中word是指定的分隔符;功能:自右而左,查找var变量所存储的字符串中,最后一次出现的word分隔符,删除此分隔符至字符串尾部之间的所有字符;

    mypath="/etc/init.d/functions"
    ${mypath%/*}:  /etc/init.d
                  
    url=http://www.magedu.com:80
    ${url##*:} :80
    ${url%%:*} : http
    
  • 查找替换:
    ${var/PATTERN/SUBSTI}:查找var所表示的字符串中,第一次被PATTERN所匹配到的字符串,将其替换为SUBSTI所表示的字符串;
    ```${var//PATTERN/SUBSTI}``:查找var所表示的字符串中,所有被PATTERN所匹配到的字符串,并将其全部替换为SUBSTI所表示的字符串;

    ${var/#PATTERN/SUBSTI}:查找var所表示的字符串中,行首被PATTERN所匹配到的字符串,将其替换为SUBSTI所表示的字符串;
    ${var/%PATTERN/SUBSTI}:查找var所表示的字符串中,行尾被PATTERN所匹配到的字符串,将其替换为SUBSTI所表示的字符串;

    注意:PATTERN中使用glob风格的通配符;

  • 查找删除:
    ${var/PATTERN}:以PATTERN为模式查找var字符串中第一次的匹配,并删除之;
    ${var//PATERN}:删除全部匹配
    ${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值;

练习:写一个脚本,完成如下功能

(1) 提示用户输入一个可执行命令的名称;
(2) 获取此命令所依赖到的所有库文件列表;
(3) 复制命令至某目标目录(例如/mnt/sysroot,即把此目录当作根)下的对应的路径中
bash, /bin/bash ==> /mnt/sysroot/bin/bash
useradd, /usr/sbin/useradd ==> /mnt/sysroot/usr/sbin/useradd
(4) 复制此命令依赖到的所有库文件至目标目录下的对应路径下;
/lib64/ld-linux-x8664.so.2 ==> /mnt/sysroot/lib64/ld-linux-x8664.so.2

进一步:
每次复制完成一个命令后,不要退出,而是提示用户继续输入要复制的其它命令,并重复完成如上所描述的功能;直到用户输入“quit”退出脚本;

[root@localhost ~]# bash /scripts/e17-1-4.sh
please input an excutable COMMAND :bash
please input an excutable COMMAND :quit      
[root@localhost ~]# tree /mnt/sysroot/
/mnt/sysroot/
├── lib64
│   ├── ld-linux-x86-64.so.2
│   ├── libc.so.6
│   ├── libdl.so.2
│   └── libtinfo.so.5
└── usr
    └── bin
        └── bash

3 directories, 5 files
[root@localhost ~]# cat /scripts/e17-1-4.sh
#!/bin/bash

sysroot='/mnt/sysroot'
function commv {
    declare -a sofiles
    cpath=`whereis $1 |cut -d' ' -f2`
    [[ -d "$sysroot`dirname $cpath`" ]] || mkdir -p $sysroot`dirname $cpath`
    cp $cpath $sysroot$cpath
    sofiles=(`ldd $cpath |grep -o '/\S*/\S\+'`)
    for i in ${sofiles[*]};do
        [[ -d "$sysroot`dirname $i`" ]] || mkdir -p $sysroot`dirname $i`
        cp $i $sysroot$i
    done
}
while true;do
    read -p 'please input an excutable COMMAND :' cname
    [[ $cname == 'quit' ]] && break
    commv $cname
done
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352