免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4658 | 回复: 9
打印 上一主题 下一主题

[学习共享] shell命令行的扩展功能 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-10-31 10:01 |只看该作者 |倒序浏览
最近学shell,看书遇到了很多疑问,实在没法子,自己啃manpage吧,这里面好多书上都是没提到的,受益匪浅,下面是我看man bash中的EXPANSION一节的学习,贴出来大家指正。
首先说一下版本:
# bash --version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.man bash中:Bash is Copyright © 1989-2009 by the Free Software Foundation, Inc.

其次推荐一本书,质量不错:《Bash Cookbook》是现在再看的,学习shell的第一本书是《Linux Command Line and Shell Scripting Bible》。其他的一些书感觉不是很好,就不提了。
进入正题。

shell中的EXPANSION功能

EXPANSION功能在命令行未进行word splitting前进行的。共以下几种,按照依次进行的顺序,列举如下:
braceexpansion, 括号扩展
tildeexpansion, ~波浪线扩展
parameterand variable expansion, 参数、变量扩展
arithmeticexpansion, 计算式扩展
commandsub-stitution, 命令替换
wordsplitting,单词分割
pathname expansion 路径扩展

只有brace expansion, word splitting, and pathname expansion能改变单词的数量。其他都是将一个单词扩展成另一个单词,也有例外:"$@"和"${name[@]}"。

[01]---brace expansion, 括号扩展

(1)Thismechanism is similar to pathname expansion,but the filenames generated need notexist。
(2)括号扩展可以嵌套的。
(3)结果的各个单词顺序是没有排序的。
(4)括号扩展的形式是:
前缀字符串{…}后缀字符串
前缀和后缀都是可选的。括号里面的内容分2种格式,
一个是逗号分割的字符串序列,
一个是顺序表达式,格式是{x..y[..incr]},x和y是整数(正负都可以,且可以前面加0调整输出的字符串宽度)或单个的字符,但必须是相同类型,incr是整数(中括号表示..incr是可选的,默认是1或-1,正负都可以,扩展只按其绝对值进行)。
{}里面至少要1个没有转义的逗号,或者正确的顺序字串,否则不进行括号扩展。
且为了防止和parameter and variable expansion, 参数、变量扩展冲突,${不进行括号扩展。
下面是举例:
# echoaa{bb,cc}dd
aabbdd  aaccdd


# echoaa{bb,cc{11,22}dd}ee   嵌套的
aabbee  aacc11ddee  aacc22ddee


# echoaa{a..f}zz 没有incr增量
aaazzaabzz aaczz aadzz aaezz aafzz


# echoaa{a..f..2}zz  字母
aaazzaaczz aaezz


# echoaa{1..9..2}zz  数字
aa1zzaa3zz aa5zz aa7zz aa9zz


# echoaa{mm,z{1..9..3}z}bb  嵌套
aammbbaaz1zbb aaz4zbb aaz7zbb


# echoaa{-20..30..-10}d  负数
aa-20d  aa-10d  aa0d aa10d  aa20d  aa30d


# echoa{01..11..3}d 调整宽度
a01d  a04d  a07d a10d


# echoa{001..011..3}d调整宽度
a001d  a004d  a007d a010d


# echoa{a..10}d 必须是相同类型
a{a..10}d


常见用途是:
       mkdir/usr/local/src/bash/{old,new,dist,bugs}
       chown root/usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}
上面还提到了和旧版本shell的兼容问题,就略过了,嘿嘿。

论坛徽章:
60
20周年集字徽章-20	
日期:2020-10-28 14:04:3015-16赛季CBA联赛之北京
日期:2016-07-06 15:42:0715-16赛季CBA联赛之同曦
日期:2016-06-12 10:38:0915-16赛季CBA联赛之佛山
日期:2016-05-27 11:54:56黄金圣斗士
日期:2015-12-02 11:44:35白银圣斗士
日期:2015-11-25 14:32:43白银圣斗士
日期:2015-11-23 12:53:352015亚冠之布里斯班狮吼
日期:2015-10-21 16:55:482015亚冠之首尔
日期:2015-09-01 16:46:052015亚冠之德黑兰石油
日期:2015-08-31 11:39:192015亚冠之萨济拖拉机
日期:2015-08-28 21:06:5315-16赛季CBA联赛之广东
日期:2016-07-12 14:58:53
2 [报告]
发表于 2013-10-31 10:04 |只看该作者
楼主看的书都是英文的呀?

论坛徽章:
0
3 [报告]
发表于 2013-10-31 10:06 |只看该作者
嗯,手握有道,啥英文都不怕,

论坛徽章:
60
20周年集字徽章-20	
日期:2020-10-28 14:04:3015-16赛季CBA联赛之北京
日期:2016-07-06 15:42:0715-16赛季CBA联赛之同曦
日期:2016-06-12 10:38:0915-16赛季CBA联赛之佛山
日期:2016-05-27 11:54:56黄金圣斗士
日期:2015-12-02 11:44:35白银圣斗士
日期:2015-11-25 14:32:43白银圣斗士
日期:2015-11-23 12:53:352015亚冠之布里斯班狮吼
日期:2015-10-21 16:55:482015亚冠之首尔
日期:2015-09-01 16:46:052015亚冠之德黑兰石油
日期:2015-08-31 11:39:192015亚冠之萨济拖拉机
日期:2015-08-28 21:06:5315-16赛季CBA联赛之广东
日期:2016-07-12 14:58:53
4 [报告]
发表于 2013-10-31 10:40 |只看该作者
回复 3# 想尼尼

那岂不是看的很吃力? 虽然我也手握有道,但还是看不懂,太菜了

论坛徽章:
0
5 [报告]
发表于 2013-10-31 10:42 |只看该作者
[02]--- tilde expansion, ~波浪线扩展

tilde-prefix(波浪线前缀词):任何以未转义~开头的单词,第一个未转义的\之前的所有字符(或不包含未转义的\的整个单词)。
若tilde-prefix中没有任何转义字符,那么tilde-prefix中除波浪线的字串认为是一个可能的login name。
若这个login name 是空字串,~被shell变量HOME替换;若HOME是unset的,那么用使用shell的当前用户的home directory替换。
若login name非空,那么用该指定用户的home directory替换。
若tilde-prefix是~+,那么用shell变量PWD替换。
若tilde-prefix是~-,那么用shell变量OLDPWD替换,若OLDPWD是unset的,那么保持原样。
若tilde-prefix是~N、~+N或~-N,N是整数,~N、~+N二者等价。这和dirs、pushd、popd这一组shell内嵌应用有关,tilde-prefix被目录堆栈中的相应项替换。
若login name是无效,或tilde expansion失败,那么字串保存原样。
另外,shell变量赋值中,在:或=后面立即检查是否有未转义的~,一旦有,也进行tilde expansion。这常用来给一些路径变量赋值。
例子:
$HOME :/root , $PWD :/home , $OLDPWD :/home/zzz
ssh登录名:root

# echo ~root  被用户root的home directory替换
/root

# echo ~  被HOME替换
/root

# echo ~+  被PWD替换
/home

# echo ~- 被OLDPWD替换
/home/zzz
# unset OLDPWD
# echo ~-
~-
# dirs
/home
# echo ~0 ~1 从0开始计算,popd,pushd什么的懒得试了,都挺简单的东西,频繁换目录时可以用下
/home ~1

论坛徽章:
2
白羊座
日期:2013-11-18 19:52:42辰龙
日期:2014-09-07 07:46:06
6 [报告]
发表于 2013-10-31 11:05 |只看该作者

论坛徽章:
0
7 [报告]
发表于 2013-10-31 14:59 |只看该作者

[03]--- Parameter Expansion, 参数扩展

$一出现,一般就是变量,命令输出,计算这几个动作。
变量名、标识一般都用{}括起来(强烈建议),${parameter}这个在有几种情况中可以很好的解决问题,比如:
VAR2=a${VAR1}b
这一类的情况等等。
${parameter}:叫做indirect expansion,它的值是以parameter的值为变量名的变量的值。感叹号和{必须是紧挨着的。举例:
aa=b
b=c
${!aa}的值是c
用途实例是:${!prefix*}${!name[@]}

下面是变量扩展的表达式,有几点说明:

下面的单词word是经过tilde expansion, parameter expansion,command substitution,

andarithmetic expansion之后的结果。

word进行扩展之前,下面式子中,若带有冒号:,那么bash检查parameter是否是unset/null的。若不带冒号:,那么bash仅仅检查parameter是否是unset的。
1${parameter:word}
parameterunsetnull的,值是word的扩展;否则是parameter的值。
举例:parameter设为abcdeabcdeworddadada
# var=abcdeabcde

# echo "${var:-dadada} ,${var-dadada}"

abcdeabcde , abcdeabcde

# var=

# echo "${var:-dadada} ,${var-dadada}"

dadada ,

# unset var

# echo "${var:-dadada} ,${var-dadada}"

dadada , dadada

2${parameter:=word}
parameterunsetnull的,值是word的扩展,且把该值赋值给parameter;否则是parameter的值。


3${parameterword}
parameterunsetnull的,向stderr输出word的扩展(若word为空串,则输出一段shell定义的message),且若shell不是交互的会退出shell;否则是parameter的值。
举例:parameter设为abcdeabcdeworddadada

#var=abcd

# echo${vardadada}

abcd
# var=

# echo${vardadada}

-bash:var: dadada

# echo${var}

-bash:var: parameter null or not set


4${parameter:+word}
parameterunsetnull的,值是NULL;否则值是word的扩展。

5${parameterffset}${parameterffset:length}
Parameter的第offset(整数是从左,负数是从右,注意:-之间要有空格)个字符开始,长度length(必须大于等于0)的字串,若:length没有,那么直到末尾。
${array[@]ffset:length},指第offset个元素开始,length个数组元素。特殊情况是:
${@ffset:length}${*ffset:length}用于位置参数$1$2等。

6${!prefix*}${!prefix@}
值是那些名字以prefix开头的变量的名字,以IFS第一个值为分割符。

# echo${!a*}

a a1 a2a3 aa


# echo${!a@}

a a1 a2a3 aa


7${!name[@]}${!name
  • }
    name是数组,扩展成数组索引列表;
    name不是数组,若是set的,那么值是0;否则是null

    #a=(1 23 4 5)

    # echo${!a[@]}

    0 1 2 34

    # unseta

    # echo${!a[@]}


    # a=

    # echo${!a[@]}

    0
    # a=100

    # echo${!a[@]}

    0

    8${#parameter}
    parameter的长度

    9${parameter#word}${parameter##word}
    其中word扩展成是类似路径扩展的pattern
    pattern匹配parameter的开头,那么${parameter#word}是删去最短匹配后剩下的串,${parameter##word}是删去最长匹配后剩下的串。
    parameter@ *,那么作用在每个位置参数上;
    parameterarray[@] array
  • ,那么作用在每个数组元素上;
    举例:

    #a=abcde

    # echo${a#ab*}  删除最短的

    cde

    # echo${a##ab*}  删除最长的


    # echo${a#?b*}  删除最短的

    cde

    # echo${a##?b*}  删除最长的


    # echo${a##b*}  不匹配开头

    abcde

    # echo${a##bcd}  不匹配开头

    abcde

    10${parameter%word}${parameter%%word}
    这二者和上面的相似,#指从parameter的开头匹配,%指从末尾匹配。
    一个%是指最短,2%指最长。

    11${parameter/pattern/string}
    匹配最长的字串。
    ${parameter/pattern/string}替换第一个
    ${parameter//pattern/string}pattern/开头,替换所有
    ${parameter/#pattern/string}pattern#开头,必须匹配开头。
    ${parameter/%pattern/string}pattern%开头,必须匹配末尾。
    ${parameter/pattern}:删除匹配的字串。
    parameter@ *,那么作用在每个位置参数上;
    parameterarray[@] array
  • ,那么作用在每个数组元素上;
    实验方法:parameter设为abcdeabcdepattern设为abcdde,三种情况,string设为111
    # var=abcdeabcde

    # echo"${var/ab/111} , ${var/cd/111} , ${var/de/111}"

    111cdeabcde, ab111eabcde , abc111abcde


    # echo"${var//ab/111} , ${var//cd/111} , ${var//de/111}"

    111cde111cde, ab111eab111e , abc111abc111


    # echo"${var/#ab/111} , ${var/#cd/111} , ${var/#de/111}"

    111cdeabcde, abcdeabcde , abcdeabcde


    # echo"${var/%ab/111} , ${var/%cd/111} , ${var/%de/111}"

    abcdeabcde, abcdeabcde , abcdeabc111


    # echo"${var//#ab/111} , ${var//#cd/111} , ${var//#de/111}"

    abcdeabcde, abcdeabcde , abcdeabcde


    # echo"${var//%ab/111} , ${var//%cd/111} , ${var//%de/111}"

    abcdeabcde, abcdeabcde , abcdeabcde


    # echo"${ var /ab} , ${ var /cd} , ${ var /de}"

    cdeabcde, abeabcde , abcabcde


    # echo"${ var //ab} , ${ var //cd} , ${ var //de}"

    cdecde, abeabe , abcabc


    # echo"${ var /#ab} , ${ var /#cd} , ${ var /#de}"

    cdeabcde, abcdeabcde , abcdeabcde


    # echo"${ var /%ab} , ${ var /%cd} , ${ var /%de}"

    abcdeabcde, abcdeabcde , abcdeabc


    这个在http://man.cx/bash(1)/zh_cn#heading14这里面版本的中文man bash把双斜杠和单斜杠放在一个等级上了,其实他属于pattern包含/、#或%三种情况中的一种而已。


    12
    ${parameterˆpattern}${parameterˆˆpattern}
    ${parameter,pattern}${parameter,,pattern}

    ^符号:匹配的子串小写转大写
    ,符号:匹配的子串大写转小写
    ^^,,是转换所有,单个的是转换第一个字符。
    parameter@ *,那么作用在每个位置参数上;
    parameterarray[@] array
  • ,那么作用在每个数组元素上;
    实验方法:parameter设为abcdeabcdepattern设为abcdde,逗号和^类似。

    #var=abcdeabcde

    # echo"${var^a}, ${var^b}, ${var^e}"

    Abcdeabcde, abcdeabcde, abcdeabcde
    # echo "${var^^a}, ${var^^b}, ${var^^e}"
    AbcdeAbcde, aBcdeaBcde, abcdEabcdE

    # echo${var^abc}  只能匹配单个字符

    abcdeabcde

    # echo"${var^a*}, ${var^a?}, ${var^^a*}, ${var^^a?}"

    Abcdeabcde, abcdeabcde, AbcdeAbcde, abcdeabcde

    # echo"${var^[abcd]}, ${var^^[abcd]}"

    Abcdeabcde, ABCDeABCDe
    这个功能学的有点蒙,manpage里面说的太过简略,我试的好多都不是想要的结果输出。


    这些个变量扩展,好多书都没提到过,不知道什么愿意,我现在看得《bash cookbook》倒是提到一些,但只是一部分。不知道是不是有版本兼容之类的问题?求大神指点。
    另外,这里面好多用的pattern,manpage里面说:
    The patternis expanded to produce a pattern just as in pathname expansion.
    只是相似,不过还是有写的区别的,这个不是很清楚,还有在下面几种情况下:
    grep ‘pattern’ *
    find $MYPATH -name 'pattern'
    [[ var==pattern ]]
    应该还有好多,暂时想不起来了。
    问题是: 这种情况的模式匹配和路径扩展(即通配符)有什么区别?求大神指点。

  • 论坛徽章:
    0
    8 [报告]
    发表于 2013-11-05 17:15 |只看该作者
    这个模式匹配和通配符的区别,总结了一下:
    1)通配符,也就是bash的路径拓展,那么每个命令行进行这种扩展的时候,结果字串必须是路径中存在的文件名。
    2)路径中的点号(.)在路径扩展中,必须精确匹配,不能用星号(*)匹配。注,bash中有个关于点号(.)在路径扩展中的行为开关。
    其他的尚未发现
    END

    论坛徽章:
    16
    IT运维版块每日发帖之星
日期:2015-10-02 06:20:00IT运维版块每月发帖之星
日期:2015-09-11 19:30:52IT运维版块每周发帖之星
日期:2015-09-11 19:20:31IT运维版块每日发帖之星
日期:2015-08-26 06:20:00每日论坛发贴之星
日期:2015-08-20 06:20:00IT运维版块每日发帖之星
日期:2015-08-20 06:20:002015年辞旧岁徽章
日期:2015-03-03 16:54:15金牛座
日期:2014-05-04 16:58:09双子座
日期:2013-12-17 16:44:37辰龙
日期:2013-11-22 15:20:59狮子座
日期:2013-11-18 22:55:08射手座
日期:2013-11-12 10:54:26
    9 [报告]
    发表于 2013-11-06 10:33 |只看该作者
    顶lz。。。

    论坛徽章:
    0
    10 [报告]
    发表于 2013-11-06 15:39 |只看该作者
    为什么不写成博客,这样你自己以后也好查阅,而让其他小白们读起来也清爽。
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

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

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP