shell脚本编程
变量:存储单个元素的内存空间;
数组:存储多个元素的连续的内存空间;
├── 数组名:整个数组只有一个名字;
└── 数组索引:编号从0开始;
数组名[索引],
${ARRAY_NAME[INDEX]}
数组引用必须要加上花括号
注意:bash-4及之后的版本,支持自定义索引格式,而不仅仅是0,1,2,...数字格式;
此类数组称之为“关联数组”
声明数组:
├── declare -a
NAME:声明索引数组;
└── declare -A
NAME:声明关联数组;(可以理解成key-value)
数组中元素的赋值方式:
- 一次只赋值一个元素;
ARRAY_NAME[INDEX]=value
- 一次赋值全部元素;
ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)
- 只赋值特定元素;
ARRAY_NAME=([0]="VAL1" [3]="VAL4" ...)
注意:bash支持稀疏格式的数组;
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
网友评论