はじめに
bash は POSIX準拠のシェルですが、加えて独自の機能拡張もなされています。
これまでは汎用性の面から拡張機能の利用は敬遠がちだった私ですが、いざ使い始めると便利で、いつの間にか手に馴染んでしまった機能が幾つかあります。
今回はその中から 中括弧による繰り返し展開 を実例とともに紹介したいと思います。
なお bash は現在、 RedHat や Ubuntu など Linux の標準ログインシェルとなっており、また Windows の WSL2(Windows Subsystem for Linux)でもそのログインシェル相当は bash になっていますので、昨今においてはシェルのデファクトスタンダードと言ってもよいかもしれません。
ただし、システムシェル(/bin/shの実体)となると話が変わり、RedHat や CentOS は bash、Ubuntu や Debian は dash、、、とOS実装系により袂(たもと)を分かちますので、この点には留意が必要です。
従来の中括弧展開
中括弧を使った展開自体は昔からあり、私も以下のようなかんじで使ってきました。
$ mkdir -p a/{bb,cc/{ddd,eee}}
### <展開後の状態>: mkdir -p a/bb a/cc/ddd a/cc/eee
$ cp hogehege.txt{,.bak}
### <展開後の状態>: cp hogehege.txt hogehege.txt.bak
中括弧による繰り返し展開
ところが最近になって「..」を使って繰返し展開ができるのを知りました。
(気づくのが遅い!?)
繰り返しの書式: {x..y[..incr]}
実際にecho文で、どのような展開になるか確認していきましょう。
$ echo {1..10}
1 2 3 4 5 6 7 8 9 10
$ echo {1..10..2}
1 3 5 7 9
$ echo {001..005}
001 002 003 004 005
$ echo {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
$ echo {a..z..3}
a d g j m p s v y
$ echo {A..C}{001..004}
A001 A002 A003 A004 B001 B002 B003 B004 C001 C002 C003 C004
実践例
例1:テスト用?に空ファイル生成(ここでは 3x8x2=48 ファイル生成)
$ touch test_{A..C}{001..008}_{01..2}.dat
$ ls
test_A001_01.dat test_A007_01.dat test_B005_01.dat test_C003_01.dat
test_A001_02.dat test_A007_02.dat test_B005_02.dat test_C003_02.dat
test_A002_01.dat test_A008_01.dat test_B006_01.dat test_C004_01.dat
test_A002_02.dat test_A008_02.dat test_B006_02.dat test_C004_02.dat
test_A003_01.dat test_B001_01.dat test_B007_01.dat test_C005_01.dat
test_A003_02.dat test_B001_02.dat test_B007_02.dat test_C005_02.dat
test_A004_01.dat test_B002_01.dat test_B008_01.dat test_C006_01.dat
test_A004_02.dat test_B002_02.dat test_B008_02.dat test_C006_02.dat
test_A005_01.dat test_B003_01.dat test_C001_01.dat test_C007_01.dat
test_A005_02.dat test_B003_02.dat test_C001_02.dat test_C007_02.dat
test_A006_01.dat test_B004_01.dat test_C002_01.dat test_C008_01.dat
test_A006_02.dat test_B004_02.dat test_C002_02.dat test_C008_02.dat
例2:指定回数繰り返す(ここでは 10 回)
$ for i in {1..10} ; do echo "$i: some command" ; done
1: some command
2: some command
3: some command
4: some command
5: some command
6: some command
7: some command
8: some command
9: some command
10: some command
以下の方法でも同じようなことができますが(これもbash拡張機能の一つ)、中括弧展開を使う方がスマートな気がします。
for ((i=0;i<10;i++)) ; do echo "$i: some command" ; done
例3: ランダムな{内容,サイズ}のバイナリファイルを100個生成
$ for i in test_{A..E}{001..020}.dat ; do \
dd if=/dev/urandom bs=$((RANDOM % 1024)) count=1 >$i ; done
$ ls -l *.dat | head -n 10
-rw-r--r-- 1 user group 649 11月 16 11:30 test_A001.dat
-rw-r--r-- 1 user group 726 11月 16 11:30 test_A002.dat
-rw-r--r-- 1 user group 973 11月 16 11:30 test_A003.dat
-rw-r--r-- 1 user group 22 11月 16 11:30 test_A004.dat
-rw-r--r-- 1 user group 599 11月 16 11:30 test_A005.dat
-rw-r--r-- 1 user group 408 11月 16 11:30 test_A006.dat
-rw-r--r-- 1 user group 807 11月 16 11:30 test_A007.dat
-rw-r--r-- 1 user group 62 11月 16 11:30 test_A008.dat
-rw-r--r-- 1 user group 685 11月 16 11:30 test_A009.dat
-rw-r--r-- 1 user group 689 11月 16 11:30 test_A010.dat
番外編
中括弧の展開は変数の評価前に実行されるため、思ったような展開にならないことがあります。
$ max=10
$ echo {1..$max}
{1..10}
とはいえ、なんとかしてこの評価を遅らせる方法もあります。
$ max=10
$ eval echo {1..$max}
1 2 3 4 5 6 7 8 9 10
そうすると、こんなことも出来ます。
$ for i in {1..10} ; do eval echo {01..$i} ; done
01
01 02
01 02 03
01 02 03 04
01 02 03 04 05
01 02 03 04 05 06
01 02 03 04 05 06 07
01 02 03 04 05 06 07 08
01 02 03 04 05 06 07 08 09
01 02 03 04 05 06 07 08 09 10
以上です。
最後までご覧いただきありがとうございます。