我们上一章介绍了()与{}的不同,这次让我们扩展一下,看看更多的变化:()与{}又是啥玩意儿呢?
在bash shell中, $()
与``(反引号)都是用来做命令替换
(command substitution)的。
所谓的命令替换
与我们第五章学过的变量替换差不多,都是用来重组命令行
:完成 `` 或者$()
里面的 命令,将其结果替换出来,再重组命令行。
例如:
$ echo the last sunday is $(date -d "last sunday" +%Y-%m-%d)
如此便可方便得到上一个星期天的日期了...^_^
在操作上, 用()或‘‘都无所谓,只是我个人比较喜欢用(),理由是:
``(反引号)很容易与''(单引号)搞混乱,尤其对初学者来说。 有时在一些奇怪的字形显示中,两种符号是一模一样的(只取两点)。 当然了有经验的朋友还是一眼就能分辨两者。只是,若能更好的避免混乱, 又何乐而不为呢? ^_^
command1 `command2 `command3` `
原来的本意是要在command2 `command3` , 先将command3替换出来给command2处理, 然后再将command2的处理结果,给command1来处理。 然而真正的结果在命令行中却是分成了`command2`与 ``。
正确的输入应该如下:
command1 `command2 \`command3\` `
要不然换成$()就没有问题了:
command1 $(commmand2 $(command3))
只要你喜欢,做多少层的替换都没有问题~~~^_^
不过,()并不是没有弊端的...首先,‘‘基本上可用在所有的unixshell中使用,若写成shellscript,其移植性比较高。而()并不是每一种shell都能使用,我只能说, 若你用bash2的话,肯定没问题... ^_^
接下来,再让我们看看吧...它其实就是用来做变量替换用的啦。一般情况下,var与var并没有啥不一样。但是用{}会比较精准的界定变量名称的范围, 比方说:
$ A=B
$ echo $AB
原本是打算先将A的结果替换出来,然后在其后补一个字母B;但命令行上,真正的结果却是替换变量名称为AB的值出来...若使用{}就没有问题了:
$ A=B
$ echo ${A}B
$ BB
不过,假如你只看到${}
只能用来界定变量名称的话, 那你就实在太小看bash了。
为了完整起见,我这里再用一些例子加以说明${}
的一些 特异功能: 假设我们定义了一个变量file为:
file=/dir1/dir2/dir3/my.file.txt
我们可以用${}
分别替换获得不同的值:
${file#*/} #其值为:dir1/dir2/dir3/my.file.txt
拿掉第一个/
及其左边的字符串,其结果为: dir1/dir2/dir3/my.file.txt
。
${file#*.} #其值为:file.txt
拿掉第一个.
及其左边的字符串,其结果为: file.txt
。
${file##*/} #其值为:my.file.txt
拿掉最后一个/
及其左边的字符串,其结果为: my.file.txt
${file##*.} #其值为:txt
拿掉最后一个.
及其左边的字符串,其结果为: txt
${file%/*} #其值为:/dir1/dir2/dir3
拿掉最后一个/
及其右边的字符串,其结果为: /dir1/dir2/dir3
。
${file%.*} #其值为:/dir1/dir2/dir3/my.file
拿掉最后一个.
及其右边的字符串,其结果为: /dir1/dir2/dir3/my.file
。
${file%%/*} #其值为:其值为空。
拿掉第一个/
及其右边的字符串,其结果为: 空串。
${file%%.*} #其值为:/dir1/dir2/dir3/my。
拿掉第一个.
及其右边的字符串,其结果为: /dir1/dir2/dir3/my。
Tips:
记忆方法:
#
是去掉左边(在键盘上#
在$
的左边);
%
是去掉右边(在键盘上%
在$
的右边);单个符号是最小匹配;
两个符号是最大匹配;
${file:0:5} #提取最左边的5个字符:/dir1
${file:5:5} #提取第5个字符及其右边的5个字符:/dir2
shell 字符串取子串的格式:${s:pos:length}
, 取字符串 s 的子串:从 pos 位置开始的字符(包括该字符)的长度为 length 的的子串; 其中pos为子串的首字符,在 s 中位置; length为子串的长度;
Note: 字符串中字符的起始编号为0.
${file/dir/path} #将第一个dir替换为path:/path1/dir2/dir3/my.file.txt
${file//dir/path} #将全部的dir替换为path:/path1/path2/path3/my.file.txt
shell 字符串变量值的替换格式:
首次替换: ${s/src_pattern/dst_pattern}
将字符串s中的第一个src_pattern替换为dst_pattern。
${s//src_pattern/dst_pattern}
将字符串s中的所有出现的src_pattern替换为dst_pattern.${file-my.file.txt}
#如果file没有设定,则使用 使用my.file.txt作为返回值, 否则返回${file};(空值及非空值时,不作处理。);
${file:-my.file.txt}
#如果file没有设定或者file为空值,均使用my.file.txt作为其返回值,否则,返回{file}.(${file} 为非空值时,不作处理);
${file+my.file.txt}
#如果file已设定(为空值或非空值), 则使用my.file.txt作为其返回值,否则不作处理。(未设定时,不作处理);
${file:+my.file.txt}
#如果${file}为非空值, 则使用my.file.txt作为其返回值,否则,(未设定或者为空值时)不作处理。
${file=my.file.txt}
#如果file为设定,则将file赋值为my.file.txt,同时将file作为其返回值;否则,file已设定(为空值或非空值),则返回{file}。
${file:=my.file.txt}
#如果file未设定或者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,否则, 非空值时,不作任何处理。Tips:
以上的理解在于,你一定要分清楚,
unset
与null
以及non-null这三种状态的赋值; 一般而言,与null有关,若不带:
, null不受影响; 若带:
, 则连null值也受影响。
${#var}
${#file} #其值为27, 因为/dir1/dir2/dir3/my.file.txt刚好为27个字符。
接下来,为大家介绍一下bash的数组(array)的处理方法。 一般而言, A="a b c def"
这样的变量只是将$A
替换为一个字符串, 但是改为 A=(a b c def)
, 则是将$A
定义为数组....
${A[@]} #方法一
${A[*]} #方法二
以上两种方法均可以得到:a b c def, 即数组的全部元素。
${A[0]}
其中,${A[0]}
可得到a, 即数组A的第一个元素, 而 ${A[1]}
则为数组A的第二元素,依次类推。
${#A[@]} #方法一
${#A[*]} #方法二
以上两种方法均可以得到数组的长度: 4, 即数组的所有元素的个数。
回忆一下,针对字符串的长度计算,使用${#str_var}
; 我们同样可以将该方法应用于数组的成员:
${#A[0]}
其中,${#A[0]}
可以得到:1,即数组A的第一个元素(a)的长度; 同理,${#A[3]}
可以得到: 3, 即数组A的第4个元素(def)的长度。
A[3]=xyz
将数组A的第四个元素重新定义为 xyz。
Tips:
诸如此类的...
能够善用bash的()与{}可以大大提高及 简化shell在变量上的处理能力哦~~~^_^
好了,最后为大家介绍$(())
的用途吧: $(())
是用来作整数运算的。
在bash中, $(())
的整数运算符号大致有这些:
例如:
$ a=5; b=7; c=2;
$ echo $(( a + b * c ))
19
$ echo $(( (a + b)/c ))
6
$ echo $(( (a * b) % c ))
1
在$(())
中的变量名称, 可以在其前面加 $
符号来替换, 也可以不用,如: $(( $a + $b * $c ))
也可以得到19的结果。
此外,$(())
还可作不同进制(如二进制、八进制、十六进制)的运算, 只是输出结果均为十进制的。
echo $(( 16#2a )) #输出结果为:42,(16进制的2a)
以一个实用的例子来看看吧 : 假如当前的umask是022,那么新建文件的权限即为:
$ umask 022
$ echo "obase=8; $(( 8#666 & (8#777 ^ 8#$(umask)) ))" | bc
644
事实上,单纯用(())
也可以重定义变量值,或作 testing:
a=5; ((a++)) #可将$a 重定义为6
a=5; ((a--)) #可将$a 重定义为4
a=5; b=7; ((a< b)) #会得到0 (true)返回值。
常见的用于(())
的测试符号有如下这些:
符号 | 符号名称 |
---|---|
< | 小于号 |
> | 大于号 |
<= | 小于或等于 |
>= | 大于或等于 |
== | 等于 |
!= | 不等于 |
Note:
使用
(())
作整数测试时, 请不要跟[]
的整数测试搞混乱了。更多的测试,我们将于第10章为大家介绍。