免费注册 查看新帖 |

Chinaunix

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

网中人“shell十三问之变量替换” 外传(初学shell必看)  关闭 [复制链接]

论坛徽章:
0
发表于 2004-09-02 16:52 |显示全部楼层
说明:这篇文原理本不是“长”这个样子。可惜由于断电缘故 ,只好根据记忆克隆了,同时也简单很多。希望起到抛砖引玉的作用!

初看第八问,不解。想:其它初学shell者亦同。故解之!

变量替换:
一:简单赋值和替换
a=bcd
$ echo $a  
bcd
$ echo ${a}
bcd

二:变量扩充
除了shell中的meta,其它的[^a-zA-Z0-9_]几乎都可以作单词边界。
同sed中关于单词边界[^a-zA-Z0-9_]的描述。
http://bbs.chinaunix.net/forum/24/20040825/393964.html
这些功能有时候会在程序中有意想不到的作用!
例如:
$ a=bcd
$ echo ${a}.b
bcd.b
$ echo $a.php
bcd.php
$ echo $a%b
bcd%b
$ echo /$a/bc
/bcd/bc
对于shell中的meta字符,则backslash。
$ echo $a\*b
bcd*b

三:变量中的变量
$ a=bcd
$ b=efg
$ c=$a$b
$ echo $c
bcdefg
$ d=$c.ghi
$ echo $d
bcdefg.ghi

思考:若变量互相嵌套,会怎样呢?

四:变量的特异功能
到网中人的啦!(ps:重写真是没激情啊)
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

其实,在“#”后面,无非就是一个匹配问题,不限于两个,你可以放任意个字符,还可以用shell中另外的通配符“?”“[…]”“[!…]”,例如:
$ echo ${file#????}
1/dir2/dir3/my.file.txt
$ echo ${file#*[0-9]}
/dir2/dir3/my.file.txt
$ echo ${file#/dir1/dir[0-9]}
/dir3/my.file.txt

“#”:相当于最小匹配,遇到一个最小的符合其后表达式的字符串(单个或多个)即中止匹配动作;
“##”:相当于最大匹配,它尽可能的匹配更多的字符。
我们可以拿“*”来说明:  
*  在shell中表示匹配任何符号包括空。当它在只有一个 # 的变量替换中,受最小匹配的影响,它不会匹配任何可打印字符,只匹配一个空,也就是什么也不匹配,你完全可以忽略它的存在;
当在有两个 ## 的变量替换中,受最大匹配的影响,一个 * 表示匹配整个字符串。
如果想匹配字符“*”时,要在“*”前加一个“\”,其后的“*”失去通配符的功能。
但是还有一种例外情况(请接着看)


例:
$ file2=abcd.efgh.ijkl.oopp
$ echo ${file2#*.*.*.*}
$ echo ${file2##*.*.*.*}

想想上面两个的输出是什么?
$ echo ${file2#*.*.*.*}
oopp
$ echo ${file2##*.*.*.*}

??知道为什么吗?因为:“*”匹配任何符号包括空。遇到一个“#”时,最后一个“*”就匹配“空”去了。看下面的:
$ echo ${file2#*.*.*.?}
opp
$ echo ${file2#*.*.*.?*}
opp
$ echo ${file2##*.*.*.?}
opp
$ echo ${file2##*.*.*.?*}

do you know?

$ echo $file3
*ab*de*cd
看看下面将输出什么?
$ echo ${file3#*ab}      
*de*cd
$ echo ${file3#**}
*ab*de*cd
$ echo ${file3##**}

$ echo ${file3#\*ab}
*de*cd
$ echo ${file3#\**}
ab*de*cd
$ echo ${file3##\**}

$ echo ${file3#*a}
b*de*cd
$ echo ${file3#\*a}
b*de*cd

不知各位有没有发现,“*”在一个“#”中时,并不一定代表“空”,它可能代表一个字符“*”也可能代表其他的什么字符,如上例的:
“$ echo ${file3#*a}”输出为“b*de*cd”,其实这还是符合最小匹配理论的。这个表达式的意思是:从变量file3的字符串左边开始删除字符,直到遇到第一个字符“a”。所以不要和“$ echo ${file3#\*a}”混淆,虽然两个结果是一样,但意思是不一样的。

再举几个例子,相信大家更容易理解这段话:
$ echo $file3
*ab*de*cd*ab*de                     //注意:出现两个“*ab”
$ echo ${file3#*a}
b*de*cd*ab*de                         //删除字符,直到出现第一个“a”,“*”为通配符
$ echo ${file3##*a}
b*de                                           //删除字符,直到出现第二个“a”,“*”为通配符
$ echo ${file3##\*a}
b*de*cd*ab*de                         //删除字符串“*a”,“*”在“\”表示字符“*”

除了通配符“*”比较难理解一点,其他的shell通配符就都很容易了。

至于“%”,和“#”不同的地方,就是从变量字串右部开始。
${file%/*}:从右部开始拿掉字符,直到遇到(从右部数起的)第一个“/” :/dir1/dir2/dir3
${file%%/*}:从右部开始拿掉字符,直到遇到(从右部数起的)最后一个“/”:(空值)
${file%.*}:从右部开始拿掉字符,直到遇到(从右部数起的)第一个“.”:/dir1/dir2/dir3/my.file
${file%%.*}:从右部开始拿掉字符,直到遇到(从右部数起的)最后一个“.”:/dir1/dir2/dir3/my

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

网中人“shell十三问之变量替换” 外传(初学shell必看)

zhichi

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

网中人“shell十三问之变量替换” 外传(初学shell必看)

辛苦了,顶!!!!

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

网中人“shell十三问之变量替换” 外传(初学shell必看)

支持

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

网中人“shell十三问之变量替换” 外传(初学shell必看)

不错.

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

网中人“shell十三问之变量替换” 外传(初学shell必看)

原帖由 "shaoping0330" 发表:
dir3/my.file.txt

“#”:相当于最小匹配,遇到一个最小的满足其内表达式的即中止删除动作。
“##”:相当于最大匹配
例:
$ file2=abcd.efgh.ijkl.oopp
$ echo ${file2#*.*.*.*}
$ echo ${file2##*.*.*.*}
..........


有几个现象很奇怪,请大侠解释一下

[root@lfs tmp]# echo ${file3#*}
*ab*de*cd
[root@lfs tmp]# echo ${file3#**}
*ab*de*cd
[root@lfs tmp]# echo ${file3#***}
*ab*de*cd

上面的3个例子,第一个容易理解,“*”匹配空了
但是为什么第二、第三个会输出同样的结果?难道所有的“*”都匹配空了?

[root@lfs tmp]# echo ${file3##*}

为什么上面的“*”没有匹配空?
是否可以这样理解,比如变量值为“*ab*de*cd”,表达式处理的时候认为值是“空*ab*de*cd空”上面的例子“*”匹配最后面的空,所以输出空。

[root@lfs tmp]# echo ${file3##\*}
ab*de*cd
[root@lfs tmp]# echo ${file3#\*}
ab*de*cd

我的理解,第一条应该输出“cd”而不是“ab*de*cd”,因为匹配最后一个“*”,可是上面的结果怎么理解?为什么第一条和第二条的结果一样?

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

网中人“shell十三问之变量替换” 外传(初学shell必看)

好,

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

网中人“shell十三问之变量替换” 外传(初学shell必看)

原帖由 "whtlly" 发表:

我的理解,第一条应该输出“cd”而不是“ab*de*cd”,因为匹配最后一个“*”,可是上面的结果怎么理解?为什么第一条和第二条的结果一样?

[root@lfs tmp]# echo ${file3##*\*}
cd
[root@lfs tmp]# echo ${file3#*\*}
ab*de*cd


呵呵,明白了,我少了一个“*”
太多的*把我弄糊涂了
但是第一个例子还是没有想清楚

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

网中人“shell十三问之变量替换” 外传(初学shell必看)

这是13问例子我怎么调不通
$ file=/dir1/dir2/dir3/my.file.txt
$ echo ${file:0:5}
替代错误???????

我的本意是找出来年(eg:2004)给变量year
date '%y'
D=`date`
year=`${$D:0:4}`
echo $year
我的不对,错在那里呀?

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

网中人“shell十三问之变量替换” 外传(初学shell必看)

上机试试就会容易理解一些,关键是“#(%)”和“##(%%)”的区别。

应该说,一个“#”:若仅出现通配符,如“*”,代表“空”;
而两个“#”:若仅出现通配符,如“*”,代表“一切”;

若加上其它特定字符后,如“*ab”在“4abty7ab”中:
一个“#”时:“*ab”尽可能匹配最小范围,如仅匹配到“4ab”就不会往下匹配;
而两个“#”:“*ab”尽可能匹配最大范围,它将匹配到整个字符串。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP