bash变量替换

1) 赋值“=”和扩充变量值
在设定变量的时侯,得遵守如下规则:
* 等号左右两边不能使用区隔符号(IFS),也应避免使用 shell 的保留字符(meta charactor)。
* 变量名称不能使用 $ 符号。
* 由字母和下划线组成,并且变量名称的第一个字母不能是数字(number)。
* 变量名称长度不可超过 256 个字母。
* 变量名称及变量值之大小写是敏感的(case sensitive)
例如:NAME=ice_walk        给变量NAME赋值为ice_walk 
在应用变量NAME的时候,在NAME前加"$"即可。
例如:echo  $NAME

扩充"(append)变量值:
除了shell中的meta,其它的[^a-zA-Z0-9_]几乎都可以作单词边界。这些功能有时候会在程序中有意想不到的作用。例如:
$ a=bcd 
$ echo $a.php                        得:bcd.php
$ echo $a%b                        得:bcd%b
$ echo /$a/bc                        得:/bcd/bc
对于shell中的meta字符,则使用backslash。
$ echo $a\*b                        得:bcd*b
用户也可以在命令行上同时对多个变量赋值,赋值语句之间用空格分开:
  X=x                Y=y                        (注意变量赋值是从右到左进行的)
  X=$Y                Y=y                        X的值是y 
X=z                Y=$Z                        Y的值是空 (变量未赋值时,shell不报错,而是赋值为空) 

内置命令eval:
在要求多于一次字符串求值的情况下可以使用内置命令 eval。例如,如果变量 X 有值 $y, 并且若 y 有值 pqr 则:eval echo $X
将回显字符串 pqr。 
一般的,eval 命令求值它的实际参数(与所有命令一样)并把这个结果作为给 shell 的输入来对待。读这个输入并执行作为结果的命令。例如:
wg=\'eval who|grep\'
$wg fred
等价于:who|grep fred
在这例子中,需要 eval 的原因是替换之后不解释元字符如 |。

局部变量
在 BASH 程序中如果一个变量被使用了,那么直到该程序的结尾,该变量都一直有效。为了使得某个变量存在于一个局部程序块中,就引入了局部变量的概念。BASH 中,在变量首次被赋初值时加上 local 关键字就可以声明一个局部变量。

C-shell的用户应该注意:
C-shell中的赋值不同于Bourne和Korn shell。C-shell使用set命令进行赋值:
$set  LOOK = /usr/mydir      (注意在等号两边要加空格,好像不加也可以)
就象文件名的置换一样,变量名的置换也是在调用程序前进行。在变量替换中,变量的值取代了变量名。例如在:$ls  $LOOK/filename  用 /usr/mydir/filename 做参数调用ls。

2) 变量替换${}
Shell 之所以强大,其中的一个因素是它可以在命令行中对变量作替换(substitution)处理。在命令行中使用者可以使用 $ 符号加上变量名称(除了在用 = 号定义变量名称之外),将变量值给替换出来,然后再重新组建命令行。
一般情况下,$var 与 ${var} 并没有啥不一样。但是用 ${ } 会比较精确的界定变量名称的范围,比方说:
$ A=B
$ echo $AB
原本是打算先将 $A 的结果替换出来,然后再补一个 B 字母于其后,但在命令行上,真正的结果却是只会提换变量名称为 AB 的值出来。若使用 ${ } 就没问题了。

A、掐头去尾
假设我们定义了一个变量为:file=/dir1/dir2/dir3/my.file.txt
我们可用 ${ } 分别替换获得不同的值:
${file#*/}        从变量file的字符串左边开始删除字符,直到第一个“/”:dir1/dir2/dir3/my.file.txt
${file##*/}        从变量file的字符串左边开始删除字符,直到最后一个“/”:my.file.txt
${file#*.}        从变量file的字符串左边开始删除字符,直到第一个“.”:file.txt
${file##*.}        从变量file的字符串左边开始删除字符,直到最后一个“.”:txt
${file%/*}        从右部开始拿掉字符,直到遇到(从右部数起的)第一个“/” :/dir1/dir2/dir3
${file%%/*}        从右部开始拿掉字符,直到遇到(从右部数起的)最后一个“/”:(空值)
${file%.*}        从右部开始拿掉字符,直到遇到(从右部数起的)第一个“.”:/dir1/dir2/dir3/my.file
${file%%.*}        从右部开始拿掉字符,直到遇到(从右部数起的)最后一个“.”:/dir1/dir2/dir3/my
记忆的方法为:
#                        是去掉左边(在键盘上 # 在 $ 之左边)
%                        是去掉右边(在键盘上 % 在 $ 之右边)
单一符号是最小匹配�r两个符号是最大匹配。
同时要注意:在 # 和 % 后可以使用任何shell中的模式匹配。并非仅限于*、.、/。

B、字串提取
${file:0:5}        提取最左边的 5 个字节:/dir1
${file:3}                去掉前面3个字符
${file:5:5}        提取第 5 个字节右边的连续 5 个字节:/dir2

C、字符串替换
${file/dir/path}                将第一个 dir 提换为 path:/path1/dir2/dir3/my.file.txt
${file//dir/path}                将全部 dir 提换为 path:/path1/path2/path3/my.file.txt
不可以使用 regexp , 只能用shell中 * 、? 的文件扩展方式。

D、通吃变量名
${!prefix*}                        代表所有以prefix开始的变量名,各变量名称之间以空格符分隔
$ ab=1 abc=2 abcd=3
$ echo ${!ab*}                        输出:ab abc abcd

E、变量赋值(没设定、空值、非空值)
${#myvar}                                计算出变量值的长度
${myvar=default}                 若 $myvar 没设定,则输出并取值 default。(保留空值及非空值) 
${myvar:=default}                 若 $myvar 没设定或为空值,则输出并取值 default。(保留非空值)
${myvar+default}                若 $myvar 设定为空值或非空值,输出但不取值 default,否则返回空(null)。
${myvar:+default}                若 $myvar 设定为非空值,输出但不取值 default,否则返回空(null)。
${myvar-default}                若 $myvar 没设定,输出但不取值 default。(保留空值及非空值)
${myvar:-default}                若 $myvar 没设定或为空值,输出但不取值 default。(保留非空值)
${myvar?default}        若 $myvar 没设定,将 default 输出至 STDERR。(不取值,保留空值及非空值)
${myvar:?default}                若 $myvar 没设定或为空值,将 default 输出至STDERR。(不取值,保留非空值)


(此表请看下面的图)



变量替换的值也可以是` `括起来的命令:$USERDIR={$Mydir:-`pwd`}
${var:?message}                        当没有指定message时,shell将显示一条默认的消息,例如:
  $UNAME=
$echo  ${UNAME:?}                        结果显示:sh:UNAME:parameter null or not set
速记法:
n        = 慈善家(你没有才给你)
n        + 商人(你有才给换)
n        - 假慈善家(表明上才给)
n        ? 牛皮精(只说不做)
n        加“:”后,相当于把“空值”也当作“unset”值处理,对有值的变量则无影响

F、bash 的组数(array)处理
一般而言,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 则是将第 4 个组数重新定义为 xyz。

3) 清除赋值:unset <变量>
变量一旦经过 unset 取消之后,其结果是将整个变量拿掉,而不仅是取消其变量值。如下两行其实是很不一样的:
$ A=
$ unset A
第一行只是将变量 A 设定为"空值"(null value),但第二行则让变量 A 不在存在:
$ A=
$ echo $A                                打印输出为空
$ unset A
$ echo $A                                打印输出为空
请务必能识别 null value 与 unset 的本质区别,这在一些进阶的变量处理上是很严格的。与export一样,unset 命令行也同样会作变量替换(这其实就是 shell 的功能之一),因此:
A=B
B=C
unset $A                                事实上所取消的变量是 B 而不是 A 。

4) $( )、` `、$(( ))、(( )) 

A、$( )与 ` `(反引号) 
都是用来做命令替换用(command substitution)的。所谓的命令替换与前面的变量替换差不多,都是用来重组命令行:完成引号里的命令行,然后将其结果替换出来,再重组命令行。
例如:$ echo last sunday is $(date -d "last sunday" +%Y-%m-%d) ,如此便可得到上一星期天的日期了。
在操作上,用 $( ) 或 ` ` 都无所谓,只是我"个人"比较喜欢用 $( ) ,理由是:
(1) ` ` 很容易与 ' ' ( 单引号)搞混乱。有时在一些奇怪的字形显示中,两种符号是一模一样的(直竖两点)。
(2) 在多层次的复合替换中,` ` 须要额外的跳脱( \` )处理,而 $( ) 则比较直观。
例如:command1 `command2 `command3` `这是错的。
原本的意图是要在 command2 `command3` 先将 command3 提换出来给command 2 处理,然后再将结果传给 command1 `command2 ...` 来处理。然而,真正的结果在命令行中却是分成了 `command2 ` 与 `` 两段。
正确的输入应该是:command1 `command2 \`command3\` `
要不然,换成 $( ) 就没问题了:command1 $(command2 $(command3))
不过,$( ) 并不是没有弊端的, ` ` 基本上可用在全部的 unix shell 中使用,若写成 shell script ,其移植性比较高。而 $( ) 并不见的每一种 shell 都能使用,只能说,若你用 bash2 的话,肯定没问题!
例:通过$()实现对某目录下文件进行操作的功能:
#!/bin/bash
j=$(ls $1)
for k in $j
do
  echo "$k"
  if [ $k = text ]
  then
    cat $k
  else
    echo no text
  fi
done

B、$(( ))用来作整数运算
在 bash 中,$(( )) 的整数运算符号大致有这些:
+ - * / :分别为 "加、减、乘、除"。
% :余数运算
& | ^ !:分别为 "AND、OR、XOR、NOT" 运算。
例:
$ 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进位转十进制)
以一个实用的例子来看看吧:
假如当前的 umask 是 022 ,那么新建文件的权限即为:
    $ umask 022
$ echo "obase=8;$(( 8#666 & (8#777 ^ 8#$(umask)) ))" | bc
644

C、用 (( ))重定义变量值或作testing
a=5; ((a++)) 可将 $a 重定义为 6
a=5; ((a--)) 则为 a=4
a=5; b=7; ((a < b)) 会得到 0 (true) 的返回值。
常见的用于 (( )) 的测试符号有如下这些:
<:小于
>:大于
<=:小于或等于
>=:大于或等于
==:等于
!=:不等于
不过,使用 (( )) 作整数测试时,请不要跟 [ ] 的整数测试搞混乱了。

 

你可能感兴趣的:(bash)