免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 9360 | 回复: 16

变量替换之 Final 版(初中级进阶必看)  关闭 [复制链接]

论坛徽章:
0
发表于 2004-09-21 09:50 |显示全部楼层
原版:网中人 shell十三问
GNU bash, version 2.05b

把关于用户变量的总结了一下(本来想再发一个,不过那就有灌水之疑,所以就发在下面了),现完整给出,希望对大家有帮助:

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
记忆的方法为:
#                        是去掉左边(在键盘上 # 在 $ 之左边)
%                        是去掉右边(在键盘上 % 在 $ 之右边)
单一符号是最小匹配﹔两个符号是最大匹配。
同时要注意:在 # 和 % 后可以使用任何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。(不取值,保留空值及非空值)
${myvardefault}                若 $myvar 没设定或为空值,将 default 输出至STDERR。(不取值,保留非空值)


(此表请看下面的图)


变量替换的值也可以是` `括起来的命令:$USERDIR={$Mydir:-`pwd`}
${varmessage}                        当没有指定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) 的返回值。
    常见的用于 (( )) 的测试符号有如下这些:
    <:小于
    >:大于
    <=:小于或等于
    >=:大于或等于
    ==:等于
    !=:不等于
    不过,使用 (( )) 作整数测试时,请不要跟 [ ] 的整数测试搞混乱了。
  • 变量替换

    变量替换

    论坛徽章:
    0
    发表于 2004-09-21 10:02 |显示全部楼层

    变量替换之 Final 版(初中级进阶必看)

    精啊~~

    论坛徽章:
    0
    发表于 2004-09-21 12:03 |显示全部楼层

    变量替换之 Final 版(初中级进阶必看)

    总结的不错!

    论坛徽章:
    0
    发表于 2004-09-21 12:08 |显示全部楼层

    变量替换之 Final 版(初中级进阶必看)

    强,,我对楼主的精神佩服的五体投地


    狂顶!!!!!!!!!!!!!!!!!!!!!!!!!!

    论坛徽章:
    0
    发表于 2004-09-21 14:35 |显示全部楼层

    变量替换之 Final 版(初中级进阶必看)

    把它移上去了!

    论坛徽章:
    0
    发表于 2004-09-21 22:36 |显示全部楼层

    变量替换之 Final 版(初中级进阶必看)

    呵呵,谢谢咯

    论坛徽章:
    0
    发表于 2004-09-22 09:06 |显示全部楼层

    变量替换之 Final 版(初中级进阶必看)

    收藏之

    论坛徽章:
    0
    发表于 2004-09-22 10:08 |显示全部楼层

    变量替换之 Final 版(初中级进阶必看)

    收藏

    论坛徽章:
    0
    发表于 2004-09-22 17:05 |显示全部楼层

    变量替换之 Final 版(初中级进阶必看)

    更新一个“通吃变量名”${!prefix*}(暗红色字体)!

    论坛徽章:
    0
    发表于 2004-10-23 16:17 |显示全部楼层

    变量替换之 Final 版(初中级进阶必看)

    好~~~~~极了~~
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP