Bash {花括号}用法

1 数组构造

基本形式是:{x..y[..incr]},x、y可以同时是整数或者单个字母,incr是一个可选项,表示增量,是一个整数。
当x、y是整数时,这个表达式扩展为包括x、y在内的所有数。整数可以前缀0,表示打印相同长度的0前缀整数。
当x、y是字母时,这个表达式扩展为包括x、y在内的所有字母(按字典序)。
当使用incr时,incr表示了每个项之间的差,默认是1。

echo {0..10}打印整数0到10。

$ echo {0..10}
0 1 2 3 4 5 6 7 8 9 10

echo {10..0}打印同样的数,不过是反向。

$ echo {0..10}
10 9 8 7 6 5 4 3 2 1

echo {10..0..2}间隔打印整数,每隔一个打印一个,从10开始,一直退到0。

$ echo {10..0..2}
10 8 6 4 2 0

echo {z..a..2}间隔打印字母,每隔一个打印一个,从z到a。

$ echo {z..a..2}
z x v t r p n l j h f d b

echo {a..c}{a..c}打印两个字母的组合,从aa到cc。

$ echo {a..c}{a..c}
aa ab ac ba bb bc ca cb cc

在Bash中,你可以这样来构造数组:

$ letter_combos=({a..z}{a..z})

letter_combos指向一个包括整个字母表中字母组合的数组。

你也可以这样:

$ dec2bin=({0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1})

dec2bin包括了所有8比特的二进制数,00000000、00000001、00000010等等,直到11111111。可以用这个数组来构造一个8比特十进制-二进制转换器。比如说你想知道25的二进制是多少,可以这么做:

$ echo ${dec2bin[25]}
00011001

2 参数扩展

这里将$和{}组合使用。

上面的dec2bin其实就涉及了参数扩展,我们来看个简单的:

$ month=("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec")
$ echo ${month[3]}
Apr

其中month是一个数组,数组中第3项(从0开始)是Apr,于是${month[3]}在扩展后就成了Apr。注意这里不能省略{},否则输出Jan[3],因为要将month[3]看成一个整体。

你也可以用参数扩展来操作变量,比如说,删除尾部的字符串:

$ a="Too longgg"
$ echo ${a%gg}
Too long

拆开来讲:

  • ${...}告诉shell要扩展这其中的内容,
  • a是要处理的变量,
  • %告诉shell你想要从变量的尾部删除字符串,
  • gg是要删除的字符串。

这个用法在转换文件格式时很方便。

ImageMagick是一系列操作和修改图像的命令行工具。其中最有用的工具是convert。在其最简单的形式下,convert可以复制并转换图像的格式。

下面的命令将一个名为image.jpg的JPEG格式图片复制并转换成名为image.png的PNG格式图片:

$ convert image.jpg image.png

利用参数扩展,你可以用以下命令达到相同效果:

$ i=image.jpg
$ convert $i ${i%jpg}png

你所做的就是从变量i中删除后缀jpg,然后再加上后缀png。

所以当你有大批量的JPEG图片需要转换时,就很方便了:

$ for i in *.jpg; do convert $i ${i%jpg}png; done

除了删除尾部字符串,还有其他操作形式:

  • ${parameter:-word}
    如果parameter未被设置或为空,就带入word;否则带入parameter的值。
  • ${parameter:=word}
    如果parameter未被设置或为空,就带入word且parameter设置为word;否则带入parameter的值。位置参数不能用这种方式赋值。
  • ${parameter:?word}
    如果parameter未被设置或为空,打印错误word并退出shell,省略word会打印错误:parameter null or not set;否则带入parameter的值。
  • ${parameter:+word}
    如果parameter未被设置或为空,就带入空,否则带入parameter的值。
    注意:上面word可以是一个变量,使用$word的形式引用其值
  • ${parameter:offset}
    截取parameter中offset开始的字符串。
  • ${parameter:offset:length}
    截取parameter中offset开始长为length的字符串。
    注意:上面的offset和length必须为整数。offset和length可以是变量,使用$offset$length引用其值
  • ${#parameter}
    表示字符串变量的长度;如果parameter是*或@,则扩展为位置参数的个数;如果parameter是数组(以month[@]形式出现),则表示数组的长度。
  • ${parameter#pattern}
    把字符串变量前缀与模式进行最小匹配,并删除匹配到的部分。
  • ${parameter##pattern}
    把字符串变量前缀与模式进行最大匹配,并删除匹配到的部分。
  • ${parameter%pattern}
    把字符串变量后缀与模式进行最小匹配,并删除匹配到的部分。
  • ${parameter%%pattern}
    把字符串变量后缀与模式进行最大匹配,并删除匹配到的部分。
  • ${parameter/pattern/string}
    使用string替换pattern的最大匹配部分。如果pattern以/开头则进行全部替换,否则只替换第一个匹配的位置;如果pattern以#开头,则匹配变量前缀;如果以%开头,则匹配变量后缀。
    注意:上面的pattern可以是变量,使用$pattern引用其值;如果parameter是*、@或数组(以month[@]形式出现),则对其中每一个元素都进行匹配操作。

3 组合输出

使用{ ... }来把多个命令的输入组合。比如有个命令:

$ echo "I found all these PNGs:"; find . -iname "*.png"; echo "Within this bunch of files:"; ls > PNGs.txt

最终输出到PNGs.txt的只有最后一个ls的输出。

$ { echo "I found all these PNGs:"; find . -iname "*.png"; echo "Within this bunch of files:"; ls; } > PNGs.txt

这样生成的PNGs.txt会包含所有输出:第一行是“I found all these PNGs:”,然后是一组用find命令找到的PNG文件名,然后是一行“Within this bunch of files:”,最后是当前目录下所有文件和目录的列表。

注意{}内部的命令前后需要有一个空格,而且命令需要以分号结尾(在脚本中可以是换行)。

4 参考

  • All About {Curly Braces} In Bash
  • bash(1) - Linux man page

你可能感兴趣的:(Bash {花括号}用法)