高级变量主要分为3个部分:变量扩展、命令替换和算术扩展。这些内容是Bash shell script程序设计的重要技巧,也是读懂程序代码的关键,必须熟练(高级必备)。在Bash Shell中,$ 运算符会触发上述3种扩展,基本形式为:- ${变量名称} #变量扩展 #例如:
${filename}
- $(命令)
#命令替换 #例如: $(ls /)
- $((算术式)) #算术扩展 #例如: $((9+9))
1、变量扩展:测试存在性及空值
变量扩展的基本型:${变量名称}
什么是变量扩展? 变量扩展是一种简易的条件判断,对不同的条件赋予变量不同的替换值。简言之,变量扩展是对基本型加上条件判断,如果条件符合,则进行变量替换,如不符合,也有相应的做法。它其实是一种隐含的“if-then-else”语法。
(1-1)“变量存在”的定义
如果变量曾设值过,则称该变量存在;反之,不曾设值过,或曾用unset取消变量,则称变量不存在或未定义。变量设值有两种情况,其值“非空”,和其值“空”(null)两种。如下所示
- myname='wsp' #变量myname的值非空
- yourname= #变量yourname值为空,其值以null表示
以上情况,表示两个变量myname和yourname是存在的,或有定义;但若用unset把它们取消,则它们就不存在,或称做没有定义。
(1-2)测试变量“存在与否”的基本用法
语法:${变量名称-默认值}
释义:若待测变量不存在,则传回-后方的默认值;但若变量存在,就传回变量的值。
- unset myname #用unset取消变量myname,因此myname不存在
- r=${myname-'wsp'} #变量myname不存在,故把“wsp”作为变量扩展结果,传回给r
- echo $r #显示 wsp
(1-3)测试变量“不存在”或其值为“空”:传回一个默认值
语法:${变量名称:-默认值}
释义:若待测变量不存在或其值为空,则传回:-后方的默认值;但若变量存在,就传回变量的值。
- myname= #myname存在,但值为空(null)
- r=${myname-'wsp'} #变量myname为空,故把“wsp”作为变量扩展结果,传回给r
- echo $r #显示 wsp
小整理: >变量扩展的条件式中只有-符号时,则只做“存在性”判断
>变量扩展的条件式是:-符号时,除了对“存在性”判断,还判断是否为空
变量扩展式 ${变量名称:-默认值}的主要用途是:在script中,变量一定要有值才行。因此,变量扩展的结果,一定要传回一个非空值(使用变量值或默认值)。另外,该变量扩展也经常会运用在script的开头,例如
- [ -n ${DEBUG:-} ] && set -v # -n 是用来测试后面接的变量是否有值,若非空,则传回真值
- # :- 后面什么都没放,表示故意要让默认值为空
- # 如果DEBUG非空,则执行set -v 否则-n就不成立,不执行&&后面
(1-4)测试变量“不存在”或其值为“空”:给变量设一个默认值
语法:${变量名称:=默认值}
释义:若待测变量不存在或其值为空,则把变量设为默认值;但若变量存在,就传回变量的值。
目的:给变量设一个默认值。
- count= #count有定义,但是值为空
- r=${count:=100} #count值为空,所以把count的值设为100
- echo $count #显示 100
(1-5)测试变量“不存在”或其值为“空”:提示错误信息
语法:${变量名称:?提示信息}
释义:若待测变量不存在或其值为空,则显示变量名和:?后面的提示信息,并立即停止执行script。
目的:确保某变量值一定要存在。
- #!/bin/bash
- fn=${1:?'错误!请提供要删除的目录的名称'} #对命令行传入的第一参数$1做检查,若是空值,
- #就显示错误信息,并停止执行该script
- echo '你要执行删除目录的指令是:'
- echo "rm -Rf ~/$fn"
(1-6)测试变量的“存在性”
语法:${变量名称:+真值}
释义:若待测变量存在且非空,则传回“真值”;否则传回空值。这里的真值,只要是非空字符串或者数字都可以。
目的:用来测试某事件的真的
- IamHappy='Feel so good.'
- r=${IamHappy:+'true'} #变量IamHappy存在且非空,传回字字符串 true
- echo $r #显示 true
2、变量扩展:取字符串切片、字符串长度
这里介绍如何运用变量扩展机制,取得字符串的某一部分(称为“切片”或“子字符串”),以及如何取得字符串长度。
(2-1)取字符串切片
字符串的第一个字符,编号为0,右邻的字符编号,依次增加1.
取字符串切片的语法有两种:
>语法一:${变量:位置起点}
释义:由指定的位置开始,截取子字符串到字符串结束
- myname="Sheller man"
- substr=${myname:4}
- echo $substr #显示子字符串:ler man
>语法二:${变量:位置起点:长度}
释义:由指定的位置开始,截取指定长度的子字符串
- filename="/etc/apache2"
- dir1=${filename:1:3}
- echo $dir1 #显示切片:etc
(2-2)取部分位置参数
这里简单的说一下命令行参数:
命令行第一个参数用$1表示,第二个用$2表示,其他依次类推。$@则代表左右的参数。例如:substr.sh x y z这个指令中,第一个参数是x,第二个参数是y,第三个参数是z。即$1的值为x,$2的值为y,$3的值为z。命令本身用$0表示,其值为substr.sh。想$0,$1,$3等变量,称为位置参数。
取得位置参数的用法有以下两式:
${@:起点} 和 ${@:起点:个数}
- #!/bin/bash
- #poz.sh
- echo $0 #显示命令本身
- echo ${@:1} #由第一个位置参数开始(第0个是$0),取得所有位置参数
- #若执行该脚本:./poz.sh first second
- #则显示结果为:
- #poz.sh
- #first second
释义:传回变量值的字符串长度
- filename="/usr/sbin/ntpdate"
- echo ${#filename} #显示字符串长度:17
除了这种方法外,计算字符串长度,还可以用外部程序expr来做:
>方法一:expr length "字符串"
说明:这里,length的expr的选项,用来指定要计算字符串长度这个操作
- str="How are you."
- len=$(expr length "$str")
- echo "str字符串的长度是: $len"
>方法二:expr "字符串":'.*'
说明:这里,:后接的.*是一个代表任意多个字符的字符串样式,expr会根据此样式来对比“字符串”,等于是计算字符串的长度
- str="How are you."
- len=$(expr "$str": '.*')
- echo "str字符串的长度是: $len"
3、变量扩展:对比样式
这里所谓“对比样式”,目的是想要截取变量值(字符串)的某一部分,其做法是:将符合样式的部分字符串删除或取代。
(3-1)由字符串前面对比,删除相符者
>语法:${变量#样式}
释义:由前面(最左边)开始,对比变量,删除“最短相符合的字符串”
- filename="/usr/sbin/ntpdate"
- r=${filename#/*/} #对比样式是/*/,意思是:凡是一对斜线之间有字符串者(空字符也可以)
- #则对比符合,因#是表示前面去最短的,对比结果为/usr/,故删去
- #传回剩下的字符串,并赋给r
- echo $r #显示结果:sbin/ntpdate
>语法:${变量##样式}
释义:由前面(最左边)开始,对比变量,删除“最长相符合的字符串”
- filename="/usr/sbin/ntpdate"
- r=${filename##/*/} #对比样式是/*/,意思是:凡是一对斜线之间有字符串者(空字符也可以)
- #则对比符合,因#是表示前面去最长的,对比结果为/usr/sbin/,故删去
- #传回剩下的字符串,并赋给r
- echo $r #显示结果:ntpdate
(3-2)由字符串后面对比,删除相符者
>语法:${变量%样式}
释义:由后面(最右边)开始,对比变量,删除“最短相符合的字符串”
>语法:${变量%%样式}
释义:由后面(最右边)开始,对比变量,删除“最长相符合的字符串”
(3-3)取代对比符合的字符串
>只替换第一个对比符合的字符串
语法:${变量/样式/替换字符串}
释义:若变量中,有符合样式的字符串(取最长的),则使用替代字符串予以取代。
>替换全部对比符合的字符串
语法:${变量//样式/替换字符串}
释义:若变量中,有符合样式的字符串(取最长的),则使用替代字符串全部予以取代。
- act="mail:x:8:8:mail:/var/mail/:/bin/sh"
- r=${act//:/,} #所有的:替换才,
- echo $r #显示结果:mail,x,8,8,mail,/var/mail,/bin/sh
(3-4)删除对比符合的字符串
>只删除第一个对比符合的字符串
语法:${变量/样式/}
释义:删除第一个符合样式的字符串
>删除全部对比符合的字符串
语法:${变量//样式/}
释义:删除所有符合样式的字符串
- act="mail:x:8:8:mail:/var/mail/:/bin/sh"
- r=${act//:/} #所有的:替换才,
- echo $r #显示结果:mailx88mail/var/mail/bin/sh
(3-4)要求样式在句首或句尾
在对比样式时,若在样式前面加上#,则该样式要出现在变量值的开头才算符合。若在样式前面加上%,则该样式需要出现在变量值的最后面才算符合。
- str="Yes, This is a TITLE"
- r=${str/#T* /} #$str中不能对比到,句首是T开头的任意长度字符串,匹配失败
- echo $r #显示结果:Yes,
This is a TITLE
4、变量扩展:取变量名称列表、数组索引列表
(4-1)取变量名称列表
语法:${!开头字符串@} 或 ${!开头字符串*}
释义:把所有以指定字符串开头的变量名称列出来,各变量之间,用$IFS定义的第一个分隔字符(通常是空格)隔开。
- filename="ntpdate"
- dir="/usr/bin"
- dir_file="$dir/$filename"
- echo ${!di@} #显示结果:dir dir_file
(4-1)取出数组索引列表
语法:${!数组变量[@]} 或 ${!数组变量[*]}
释义:把数组变量多有的索引列出,各索引值之间,用$IFS定义的第一个分隔字符(通常是空格)隔开。
- ar=(a b c xy z)
- r=${!ar[@]}
- echo $r #显示结果:0 1 2 3 4
5、命令替换
所谓的命令替换,是把命令执行后的标准输入放入变量中。例如说,想查看工作目录中的所有的文件名,可以执行ls命令,但如何把这些文件名存入变量中,供往后的程序代码再利用呢?使用命令替换,可以轻松做到。
命令替换语法: 变量名称=$(命令)
- #!/bin/bash
- tmp=$(ifconfig eth0 | grep 'inet addr') #获取eth0网卡的ip资料
- r=${tmp/inet addr:/} #删除
inet addr:
- ip=${r/ Bacst*/} #删除
Bacst及其后面的字符,剩下的就是ip地址
- echo $ip #显示ip
为什么是8+16这个字符串呢?而不是24? 因为Bash的变量,默认没有数据类型,全部以字符串视之。因此8+16对Bash来说只是个字符串,并不进行算术运算。那在Bash中,如何进行算术运算? 方法很多,这里先介绍算术扩展。
算术扩展语法:$((算术式))
- I=$((8+16))
- echo $I #显示结果:24
地方
阅读(1335) | 评论(0) | 转发(0) |