それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

bash のブレース展開機能の紹介と用例

bash のブレース展開機能が強化されている

bash 4.0 から、bash のブレース展開機能が強化されています。

bash のブレース展開の使い方を紹介したいと思います。

bash ゼロ埋め展開機能

数字のゼロ埋めができるようになっています

ゼロ埋めの例1
echo {00000..10}
echo {00..10}

実際の例

$ for i in {000..3}; do echo $i.jpg ; done ;
000.jpg
001.jpg
002.jpg
003.jpg

従来は、printf と組み合わせる必要があったのですが、コレがとても楽になっています。

bash の ブレース展開の増分値を指定

偶数の増分値や、5飛び飛びの値で出すことができるようになっています。

ゼロ埋めの例2 増分指定
echo {00..10..2}.jpg ;

実際の例

takuya@Desktop$ for i in {00..10..2}; do echo $i.jpg ; done ;
00.jpg
02.jpg
04.jpg
06.jpg
08.jpg
10.jpg

これは余り使わない??10ごと、100ごとなら少し使うかもしれない。

ブレース展開について

そもそもbash のブレース展開についてご存知でしょうか。しっかりおさらいしておきたいと思います。

bash には {} curly brace で囲った部分を展開する機能があります。

brace 展開の例

シンプルなブレース展開の例
echo {a,b,c,d}  #-> a b c d 

{a,b,c,d} とカンマ区切りで文字を指定したら、そこがすべて展開されて、スペース区切りに解釈されます。

連番にブレース展開する。

ブレース展開は、とくに連番で威力を発揮します。

先程の例の {a,b,c,d} は a-d でひとつづきなのでさらに省略して記述することが出来ます。

連番ブレース展開の例1
echo {a..d} #-> a b c d 

連番は、文字でも数字でもどちらでも利用することが出来ます。

連番ブレース展開の例2
echo {1..10} # =>1 2 3 4 5 6 7 8 9 10

1..10 と書けば、これが10個の数字に展開されます。便利ですよね。

さらに冒頭のbash4.0 の追加機能と合わせれば、数字を0パディングして美しいファイル名を作ることが出来ます。

ブレース展開の活用

ブレース展開は、さまざまに活用して威力を発揮します。幾つか例を見ていきます。

連番はfor ループと合わせて威力を発揮します。

たとえば、連番nファイル名を作る場合は、とても簡単に作ることができるようになりました。

for i in {00..15}; do 
  echo $i.jpg
done
#
00.jpg
01.jpg
02.jpg
(中略
15.jpg

日付もぱぱっと作れます

たとえば、10日分の日付をあっという間に作ることも出来ます。

日付をサクッと作る例1
takuya@Desktop$ for i in {00..10}; do date -I --date "+$i days"; done
2016-12-21
2016-12-22
2016-12-23
2016-12-24
2016-12-25
2016-12-26
2016-12-27
2016-12-28
2016-12-29
2016-12-30
2016-12-31

増分を使えば、毎週水曜日もぱぱっと作れます

直近50日で、今日(水曜日)から7日おきに毎週の日付を計算すると次のようになります。

日付をサクッと作る例2
takuya@Desktop$ for i in {00..50..7}; do date  --date "+$i days"; done
水 12 21 17:44:29 JST 2016
水 12 28 17:44:29 JST 2016
水  1  4 17:44:29 JST 2017
水  1 11 17:44:29 JST 2017
水  1 18 17:44:29 JST 2017
水  1 25 17:44:29 JST 2017
水  2  1 17:44:29 JST 2017
水  2  8 17:44:29 JST 2017

楽ちんですねー。増分はカレンダーなど繰り返しのあるものと組み合わせると記憶しやすいです。

ブレース展開と文字列の組み合わせ

文字列のブレース展開は、BASEとなる文字列と組み合わせて使うことが出来ます。

連番.jpg のように拡張子を含める場合
touch {00..10}.jpg
名前-連番.jpg のように拡張子に名前をを含める場合
touch some-image-{00..10}.jpg
ディレクトリ名を含める場合
touch path/to/image-{00..10}.jpg

これらのように、bash のブレース展開による文字列展開は、かなり柔軟に使えます。

ファイルのコピーにブレース展開を使う。

ファイルのコピーをするときにブレース展開を使うと少し楽になります。

ファイルコピーの例1
touch my-file.txt  # ファイル作成
cp my-file.{txt,back}  # ファイルコピー

これは、 cp my-file.{txt,back}cp my-file.txt my-file.back にブレース展開されるので、無駄なファイル名を書かずに済みます。 さらに、ファイル名の置換などを組み合わせると更に楽に記述することが出来ます。

ブレース展開の第一番の省略

ブレース展開の第一番目の要素を省略すると、何も補完されない文字に展開されます。

つまり、これは次のようになります。

ファイルコピーの例2
cp image.jpg{,.back}  # cp image.jpg image.jpg.back

これは image{,back} と先頭カンマの前に何もないので image.jpg image.jpg.back に展開されるのです

もちろん、重要なファイルは此のようなバックアップではなくgit などを使うべきですが。 ワーキングファイルを作るときには重宝します。

変数とも組み合わせできる。

連番を作るときに、その初期値や最大値(max)を、あとで指定したい時があります。

此のようなときは変数を使うのですが、ブレース展開中では変数を使うことが出来ません。

変数とブレース展開:出来ない例
$ max=10
$ echo {1..$max} #=>{1..10}

変数をeval する

変数を組み合わせたいときは、evalをする必要があります。

変数とブレース展開:実現可能な例
$ max=10
$ eval echo {1..$max} #=> 1  2  3 4 5 6 7 8 9 10 

このようにして、変数と組み合わせて戦えます。

これは、詳しく書くと次のように解釈されています。

$ max=10
$ set -x 
$ eval echo  {1..${max}}
+ eval echo '{1..10}'   # eval に渡される前に 変数が展開される
++ echo 1 2 3 4 5 6 7 8 9 10 # eval 時に ブレースが展開される
1 2 3 4 5 6 7 8 9 10

ブレース展開✕ブレース展開

ブレース展開は行列のように考えることが出来ます。

つまり ブレース展開✕ブレース展開 のような組み合わせも可能になっています。

複数のブレース展開を組み合わせる例1
echo {A..C}{1..3} # => A1 A2 A3 B1 B2 B3 C1 C2 C3
複数のブレース展開を組み合わせる例2
echo {{A..C},{1..3}} #=> A B C 1 2 3

このように、要素の掛け合わせや、要素の併合もできるようになっています。

上記の例は、連番展開をしたうえでその展開後のブレース展開を更に行っています。

これは、もちろん、連番展開を使わない場合にも有効です。

複数のブレース展開の展開の例3
echo {F,G,H}{10,20,24} #=>F10 F20 F24 G10 G20 G24 H10 H20 H24
echo {{F,G,H},{10,20,24}} #=> F G H 10 20 24

ブレース展開✕ブレース展開で、for ループのネスト記述から脱却することが出来ると思います。

最後に

どうでしょう、bash のブレース展開を便利に使えそうなイメージが湧いたでしょうか。

デフォルトシェルでどこでも使えるbashなのですが、そのブレース機能はあまり知られていない気がします。

まとめ

つぎに、bash の使い方としてブレース展開の例をまとめておきます。

最初に、連番展開を覚えるところから使い始めると便利さを実感できると思います。

ブレース記述 展開後の文字列
touch {a,b} touch a b
touch {a,b}.jpg touch a.jpg b.jpg
touch image{,.b}.jpg touch image.jpg image.b.jpg
touch {1..5} touch 1 2 3 4 5
touch {001..5} touch 001 002 003 004 005
touch {000..5..10} touch 000.jpg 010.jpg 020.jpg 030.jpg 040.jpg 050.jpg
touch {a..c}.jpg touch a.jpg b.jpg c.jpg
touch {a..c}{1..3}.jpg touch a1.jpg a2.jpg a3.jpg b1.jpg b2.jpg b3.jpg c1.jpg c2.jpg c3.jpg
touch {{a..c},{1..3}}.jpg touch a.jpg b.jpg c.jpg 1.jpg 2.jpg 3.jpg

さらに

文字列の置換も出来ます。

  • ${parameter%word} 後方マッチ削除
  • ${parameter%%word} 後方マッチ削除(最長マッチ)
  • ${parameter#word} 前方マッチ削除
  • ${parameter##word} 前方マッチ削除(最長マッチ)
  • ${parameter/search/replacement} マッチ置換

takuya-1st.hatenablog.jp

参考資料

http://wiki.bash-hackers.org/syntax/expansion/brace