一、定义
所谓的变量,就是就是利用一个特定的"名称"(name)来存取一段可以变化的"值"(value),简单说来就是“用一个名称储存一个数值”。
二、设定(=)
1. 如何设定变量
在 bash 中,你可以用"=" 来设定或重新定义变量的内容:
name=value
2. 规则
在设定变量的时侯,得遵守如下规则:
- 等号左右两边不能使用字符分隔符(IFS),也应避免使用shell的其他元字符(meta charactor)。
- 变量名称不能使用 $ 符号。
- 变量名称的第一个字母不能是数字(number)。
- 变量名称长度不可超过 256 个字母。
- 变量名称及变量值之大小写是有区别的(case sensitive)。
三、取消设定(unset)
1. 取消变量
要取消一个变量,在bash 中可使用 unset 命令来处理:
unset 变量名
变量一旦经过 unset 取消之后,其结果是将整个变量拿掉,而不仅是取消其变量值,如下两行其实是很不一样的:
$ A=
$ unset A
第一行只是将变量 A 设定为"空值"(null value),但第二行则让变量 A 不在存在。虽然用echo命令输出都是一样的结果,但是在变量替换的时候却有着不同的效果。如:
${unknow=new}:若$unknow没有设定(unset),则使用new作为传回值,同时将unknow赋值为new,若unknow为空值或者非空值,则new对传回值与unknow均不影响,因此对于一个变量,它有只仅有三种状态:
- 非空值(not null)
- 空值(null)
- 不设定(unset)
四、变量替换
1.普通替换
在命令行中使用者可以使用 $ 符号加上变量名称(除了在用 = 号定义变量名称之外),
将变量值给替换出来,然后再重新组建命令行。
比方:
A=ls B=la C=/tmp $A -$B $C
在上面的最后一行命令中,在被执行之前(在输入 CR 字符之前),$符号会对每一个变量作替换处理(将变量值替换出来再重组命令行),最后会得出如下命令行:
ls -la /tmp
若从技术细节来看,shell会依据IFS将command line所输入的文字给拆解为"字段"(word)。然后再针对元字符(meta)先作处理,最后再重组整行command line。这里的 $ 就是 command line 中最经典的 meta 之一了,就是作变量替换的。
2. 变量扩充
我们也可利用命令行的变量替换能力来"扩充"(append)变量值:
A=B:C:D
A=$A:E
这样,第一行我们设定 A 的值为 "B:C:D",然后,第二行再将值扩充为 "B:C:D:E" 。上面的扩充范例,我们使用区隔符号(:)来达到扩充目的,要是没有区隔符号的话,如下是有问题的:
A=BCD
A=$AE
因为第二次是将 A 的值继承 $AE 的提换结果,而非 $A 再加 E ﹗要解决此问题,我们可用更严谨的替换处理:
A=BCD
A=${A}E
上例中,我们使用 {} 将变量名称的范围给明确定义出来,如此一来,我们就可以将 A 的变量值从 BCD 给扩充为 BCDE 。
3. ${}变量替换
(1)一般情况下,$var 与 ${var} 并没有啥不一样。
但是用${ }会比较精确的界定变量名称的范围,但更高级的用法是用来进行变量替换,假设我们定义了一个变量为:
file=/dir1/dir2/dir3/my.file.txt
我们可以用 ${ } 分别替换获得不同的值:
${file#*/}:拿掉第一条 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt ${file##*/}:拿掉最后一条 / 及其左边的字符串:my.file.txt ${file#*.}:拿掉第一个 . 及其左边的字符串:file.txt ${file##*.}:拿掉最后一个 . 及其左边的字符串:txt ${file%/*}:拿掉最后条 / 及其右边的字符串:/dir1/dir2/dir3 ${file%%/*}:拿掉第一条 / 及其右边的字符串:(空值) ${file%.*}:拿掉最后一个 . 及其右边的字符串:/dir1/dir2/dir3/my.file ${file%%.*}:拿掉第一个 . 及其右边的字符串:/dir1/dir2/dir3/my
记忆的方法为:
[list]# 是去掉左边(在键盘上 # 在 $ 之左边) % 是去掉右边(在键盘上 % 在 $ 之右边) 单一符号是最小匹配﹔两个符号是最大匹配。[/list] ${file:0:5}:提取最左边的 5 个字节:/dir1 ${file:5:5}:提取第 5 个字节右边的连续 5 个字节:/dir2
(2) 对变量值里的字符串作替换(接上面的例子):
file=/dir1/dir2/dir3/my.file.txt ${file/dir/path}:将第一个 dir 替换为 path:/path1/dir2/dir3/my.file.txt ${file//dir/path}:将全部 dir 提换为 path:/path1/path2/path3/my.file.txt
(3) 针对不同的变量状态赋值(没设定、空值、非空值):
${file-my.file.txt} :假如 $file 没有设定,则使用 my.file.txt 作传回值。(空值及非空值时不作处理) ${file:-my.file.txt} :假如 $file 没有设定或为空值,则使用 my.file.txt 作传回值。 (非空值时不作处理) ${file+my.file.txt} :假如 $file 设为空值或非空值,均使用 my.file.txt 作传回值。(没设定时不作处理) ${file:+my.file.txt} :若 $file 为非空值,则使用 my.file.txt 作传回值。 (没设定及空值时不作处理) ${file=my.file.txt} :若 $file 没设定,则使用 my.file.txt 作传回值,同时将 $file 赋值为my.file.txt 。 (空值及非空值时不作处理) ${file:=my.file.txt} :若 $file 没设定或为空值,则使用 my.file.txt 作传回值,同时将 $file 赋值为 my.file.txt 。(非空值时不作处理) ${file?my.file.txt} :若 $file 没设定,则将 my.file.txt 输出至 STDERR。 (空值及非空值时不作处理) ${file:?my.file.txt} :若 $file 没设定或为空值,则将 my.file.txt 输出至 STDERR。 (非空值时不作处理)
以上的理解在于,你一定要分清楚unset与null及non-null这三种赋值状态。一般而言,:与null有关,若不带:的话,null不受影响,若带:则连null也受影响。还有哦,${#var}可计算出变量值的长度:
${#file} 可得到 27 ,因为/dir1/dir2/dir3/my.file.txt 刚好是 27 个字节...
(4) 用来处理数组
一般而言,A="a b c def" 这样的变量只是将 $A 替换为一个单一的字符串,但是改为 A=(a b c def) ,则是将 $A 定义为组数...
bash 的组数替换方法可参考如下方法:
${A[@]} 或 ${A[*]} 可得到 a b c def (全部组数) ${A[0]} 可得到 a (第一个组数),${A[1]} 则为第二个组数... ${#A[@]} 或 ${#A[*]} 可得到 4 (全部组数数量) ${#A[0]} 可得到1 (即第一个组数(a)的长度),${#A[3]}可得到 3 (第四个组数(def)的长度) A[3]=xyz 则是将第四个组数重新定义为 xyz ...
五、export
严格来说,我们在当前shell中所定义的变量,均属于"本地变量"(local variable),只有经过 export 命令的"输出"处理,才能成为环境变量(environment variable):
$ A=B
$ export A
或
$ export A=B
经过 export 输出处理之后,变量 A 就能成为一个环境变量供其后的命令使用。
六、参考
1. shell十三问
(完)