本篇博客我们来讨论一下bash shell中的变量的使用。
声明变量和取消变量
声明变量时,语法是name=value
,左侧是变量名,右侧是变量的值,中间的等号两侧没有空格。
$ str=hello
$ echo $str
hello
取消变量使用unset name
的形式
$ unset str
$ echo $str
访问变量
从上面可以看出,访问变量时是使用$name
的形式。
除此之外,在声明变量时还可以在双引号内引用变量
$ str=hello
$ msg="$str,world"
$ echo $msg
hello,world
在双引号内,变量的值会被计算,而如果使用单引号的话,则引号内的所有变量都不会被计算。
变量的作用域
在bash中,变量可以分为两类,分别是环境变量和自定义变量,环境变量相当于全局变量,而自定义变量相当于局部变量。环境变量可以被子进程所访问,而自定义变量则不能被子进程访问到。
通过export
关键字,可以将自定义变量升级为环境变量。
接着上面的msg变量,直接输入bash
命令开启一个子进程,然后msg
变量是不能被访问到的
$ bash
$ echo $msg
接下来使用export
关键字来将msg
升级为环境变量,再进入子进程,该变量就能够被访问到了
$ exit
exit
$ export msg
$ bash
$ echo $msg
hello,world
变量的类型
在bash shell中,可以使用declare
关键字来声明变量的类型。declare的用法如下:
declare [-aixr] varable
参数:
-a 将后面的变量声明为数组类型(array)
-i 将后面的变量声明为整数类型(integer)
-x 同export,将后面的变量声明为环境变量
-r 将变量声明为readonly类型,只读。
来看一个跟变量类型相关的例子
$ sum=1+2+3
$ echo $sum
1+2+3
很显然,这个变量的内容和我的预期是不一致的,我希望看到的结果是计算出一个和。这时候,就可以使用declare
关键字声明一个integer类型的变量
$ declare -i sum=1+2+3
$ echo $sum
6
除此之外还有一种专门用来做计算的形式:$((exp))
,来看一个例子
$ sum=$((1 + 2 + 3))
$ echo $sum
6
表达式中间还可以加空格。
变量的删除和替换
这是一个很有意思的机制。先来看个例子吧。
删除
$ msg=hello,world
$ echo ${msg#hello,}
world
${}
是外层的,来启动删除或替换模式
#
表示从开头位置删除,并且删除的越少越好
接下来看看两个井号的功能。
$ msg="hello,world;hello,linux"
$ echo ${msg##hello*,}
linux
可以看出来,两个井号的功能是从开头位置删除,并且删除的越多越好。里面还有一个*
号,表示任意多个字符,所以就直接删除到了最后一个逗号。
除此之外,还有一个特殊的符号是%
。%
表示从结尾处开始删除,并删除的越少越好,而%%
表示从结尾位置开始删除,并删除的越多越好。
$ msg="hello,world;hello,linux"
$ echo ${msg%%,*}
hello
替换
除了删除的四种用法外,还有两种替换的方式
$ msg="hello,world;hello,linux"
$ echo ${msg/hello/HELLO}
HELLO,world;hello,linux
第一个/
后面是旧字符,第二个/
后面是新字符,结果就是:搜索第一组旧字符并替换为新字符(只替换一次)。还可以用两个斜杠//
来替换全部关键字
$ msg="hello,world;hello,linux"
$ echo ${msg//hello/HELLO}
HELLO,world;HELLO,linux
变量的测试与内容替换
变量的测试与内容替换主要包含几个特殊符号,分别是-
,+
,?
。下面先来说一下减号-
。减号前面是被测试的变量,后面是默认值,意思是,如果被测试的对象没有定义,则使用减号后面给出的默认值。测试与替换的表达式需要写到${}
里面才会被执行。下面来看个例子
首先,unset上面用到的的所有变量
$ unset msg
$ unset str
然后给msg赋值,并且测试str的内容
$ msg=${str-defaultvalue}
$ echo $msg
defaultvalue
由于str是空的,所以这个测试表达式使用的是减号后面的默认值。再来看一个被测试的变量有值的情况。
$ str2="i have value"
$ msg2=${str2-defaultvalue}
$ echo $msg2
i have value
上面的变量str2是有值的,所以,默认值没有生效。
有一种特殊的情况是,如果被测试的变量定义了,但值是空字符串,这种情况的结果往往会违背我们的预期。如果希望值为空字符串的变量也能在被测试后使用默认值,可以使用-:
。
关于加号+
的测试,结果与减号-
正好相反,如果被测试的对象有定义,则替换为加号后面的值,否则,则忽略。看一个例子
$ str="i hava value"
$ msg=${str+"another value"}
$ echo $msg
another value
加号+
也可以配合冒号一起使用,则是+:
,意思是空字符串也不会被替换。
加冒号的情况下,空字符串视为没有定义,结果与没有定义时是一样的。
还有一种问号?
的情况,意思是如果变量没有定义,问号后面的值会被输出到stderr中。同样可以配合冒号一起使用?:
,意思是被测试的变量是空字符串时,问号后面的内容也会被发送到stderr中。下面来看个例子
$ unset msg
$ unset str
$ msg=${str?"undefined !"}
bash: str: undefined !
变量的substring
${parameter:offset}
${parameter:offset:length}
语法如上。
$ name='hello,world'
${name:2:3}
llo
$ echo ${name:2}
llo,world
$ echo ${name: -3}
rld
如果参数小于0,则数字前面要带有一个空格。参数小于0的意思是从后往前取一个固定长度的子串。