bash之花括号展开(brace expansion)


为什么写本篇文章

之前在写《bash之通配符》时查阅bash文档才了解到通配符只是bash很多种“扩展(expansion)”功能中的一个知识点而已,顿感自己对bash的了解是太少了,加上工作天天会使用到bash,因此觉得很有必要对bash的各种扩展功能做个总结,方便自己日后查阅学习。

这里再一次列出bash的所有扩展如下:

  • Brace Expansion (花括号扩展)
  • Tilde Expansion (波浪号扩展)
  • Parameter and and Variable Expansion (参数和变量扩展)
  • Command Substitution (命令置换)
  • Arithmetic Expansion (算数扩展)
  • Word Splitting (单词分割)
  • Pathname Expansion (路径扩展)

注意,上面列举的顺序正是bash在扩展时的顺序。以下这张图是在《Learning the bash Shell》中截取的,非常直观!


这里需要指出的是,上图陈列的顺序是bash的,而其他的shell扩展顺序可能稍微有所区别!

由于篇幅的限制,打算一篇博文只讲一种扩展,本篇详细说明第一个扩展,即花括号扩展。


花括号展开de定义(brace expansion)

花括号扩展有时在别的书籍中也被称为大括号扩展,是可以让bash生成任意字符串的一种扩展功能。它与后面会提到的“路径扩展”非常相似,唯一不同的是生成的字符串可以是不存在的路径或者文件名

在bash中,花括号扩展在诸多扩展中的优先级最高,因此像类似于echo {a,b}$PATH的语句在完成花括号扩展之后的结果应该为a$PATH b$PATH,而对PATH环境变量的扩展需要到后续的“参数和变量扩展”阶段才开始。


花括号扩展的两种格式

花括号扩展的使用大体上分为两类:

第一类格式为

preamble+{string1,string2,...,stringN}+postscript

左右的花括号是必须的,中间的字符串列表分别由逗号隔开,注意逗号前后不能有空格,如果string中有空格,则需要用单引号或者双引号括起来。

bash在实际扩展时,会将preamble和花括号种的所有字符串(按照从左到右的顺序)相连,最后分别加上postscript。

此外,花括号中间至少有一个逗号,否则bash不会认为这是括号扩展,例如echo {money}就只会输出{money},想要输出money,需要改为echo {money,},如下:

[17:43:01@astrol:/tmp]$ echo {money}
{money}
[17:45:04@astrol:/tmp]$ echo {money,}
money


再来两个完整的列子吧:

[17:40:19@astrol:~/work/rootfs]$ echo sp{el,il,al}l
spell spill spall

[17:40:30@astrol:~/work/rootfs]$ echo sp{el,il, al}l  #al之前有空格,原样输出
sp{el,il, al}l

[17:40:33@astrol:~/work/rootfs]$ echo sp{el,il," al"}l
spell spill sp all

[17:40:37@astrol:~/work/rootfs]$ echo sp{el,il,' al'}l
spell spill sp all

[17:40:44@astrol:~/work/rootfs]$ echo sp{el,il," "al}l
spell spill sp all

[17:40:50@astrol:~/work/rootfs]$ echo sp{el,il,' 'al}l
spell spill sp all
注意观察对空格的处理哦!


第二类格式为

preamble+{<START>..<END>[..<INCR>]}+postscript


其中<START>..<END>组合而成的表达式术语叫做序列表达式(sequence expression),表示一个特定的范围。当<START>和<END>是数字时,代表的是数字范围;当<START>和<END>是单个字母时,代表的是字符范围(默认LC_ALL字符排序)。<START>和<END>必须同为数字或者字母,否则bash不认为是花括号扩展,而是原样输出。来看几个常用的例子:

[17:57:59@astrol:~]$ echo {0..12}
0 1 2 3 4 5 6 7 8 9 10 11 12

[17:58:09@astrol:~]$ echo {3..-2}
3 2 1 0 -1 -2

[17:58:14@astrol:~]$ echo {a..g}
a b c d e f g

[17:58:19@astrol:~]$ echo {g..a}
g f e d c b a


其中的<INCR>是可选的,代表的是区间范围的递增数,它必须是数字。例如:

[19:11:26@astrol:~]$ echo {0..10..2}
0 2 4 6 8 10

从0开始,每递增2个数字就取出相应数字。

如果不指定<INCR>,那么默认是1或者是-1,具体是1还是-1,要看前面区间范围是递增的还是递减的,比如上面例子的{a..g}中<INCR>默认为1,{g..a}中<INCR>默认为-1。
另外,当<START>和<END>是数字时,我们可以通过在数字前面加0来使输出结果的长度保持一致,例如:

[19:15:19@astrol:~]$ echo {1..10}
1 2 3 4 5 6 7 8 9 10

[19:15:24@astrol:~]$ echo {01..10}
01 02 03 04 05 06 07 08 09 10

[19:15:26@astrol:~]$ echo {001..10}
001 002 003 004 005 006 007 008 009 010

这样格式长度一样,会显得很美观。


我们可以组合使用花括号扩展:

[19:20:18@astrol:~]$ echo {a..z}{0..9}
a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 g0 g1 g2 g3 g4 g5 g6 g7 g8 g9 h0 h1 h2 h3 h4 h5 h6 h7 h8 h9 i0 i1 i2 i3 i4 i5 i6 i7 i8 i9 j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 k0 k1 k2 k3 k4 k5 k6 k7 k8 k9 l0 l1 l2 l3 l4 l5 l6 l7 l8 l9 m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 n0 n1 n2 n3 n4 n5 n6 n7 n8 n9 o0 o1 o2 o3 o4 o5 o6 o7 o8 o9 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 q0 q1 q2 q3 q4 q5 q6 q7 q8 q9 r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 u0 u1 u2 u3 u4 u5 u6 u7 u8 u9 v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 w0 w1 w2 w3 w4 w5 w6 w7 w8 w9 x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 y0 y1 y2 y3 y4 y5 y6 y7 y8 y9 z0 z1 z2 z3 z4 z5 z6 z7 z8 z9


还可以嵌套使用花括号扩展:

[19:20:19@astrol:~]$ echo {{A..Z},{a..z}}
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z

先扩展外层的花括号,结果为 {A..Z}和{a..z},然后分别扩展这两个花括号,结果就如上所示。

来个复杂点的:

[19:23:57@astrol:~]$ printf "%s\n" img{00{1..9},0{10..99},{100..999}}.png
<输出省略>

其中img{00{1..9},0{10..99},{100..999}}.png先扩展最外层花括号,结果为:

img00{1..9}.png  img0{10.99}.png  img{100..999}.png

然后从左到右,分别扩展各个花括号(即内层花括号)。

最后需要强调的一点是:花括号扩展是bash特有的特性,传统的sh是不支持的。我们可以通过使用set +B来关闭花括号扩展功能,相反的,用set -B使能该功能。

[19:31:04@astrol:~]$ echo file{1,2}
file1 file2
[19:31:04@astrol:~]$ set +B
[19:31:07@astrol:~]$ echo file{1,2}
file{1,2}

Over !!!


参考链接:

Brace expansion

Bash Brace Expansion

Bash Brace Expansion Tutorial: 6 Examples of Expanding Expressions within Braces

Brace expansion with variable?

《 bash学习之八:shell expansion(shell扩展)

bash shell 中的扩展--花括号扩展和波浪线扩展


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2018 ITdaan.com 粤ICP备14056181号