Bashブレース展開チュートリアル:波括弧{}で式を展開する6つの実例
Bashシェルの展開(Expansion)とは
シェルが入力を解析する際に実行する処理の一つが「シェル展開」です。Bashにはさまざまな種類の展開機能が用意されており、本記事ではその中でも特に重要な「ブレース展開(波括弧展開)」について詳しく解説します。
この記事は、連載中のBashチュートリアルシリーズの一部です。
ブレース展開の基本
ブレース展開は、任意の文字列を生成するための機能です。1つの引数から複数のコマンドライン引数を簡単に作成できます。波括弧 {} 内に指定した文字列に対して、前後に置く文字列(プレアンブル/ポストスクリプト)を組み合わせることで、すべての組み合わせが自動的に生成されます。プレアンブルは波括弧内の各文字列の先頭に付加され、ポストスクリプトは各結果文字列の末尾に追加されます。展開は左から右へと行われます。
$ echo last{mce,boot,xorg}.log
lastmce.log lastboot.log lastxorg.log
※ 「last」がプレアンブル、「.log」がポストスクリプトです
上記のecho文では、3つのログファイルを個別に指定する手間が省けます。lastbootログ・MCEログ・Xorgログの内容をまとめて確認したい場合などに、ブレース展開が非常に役立ちます。
1. ブレース展開を使ったバックアップの例
$ cat bkup.sh
set -x # コマンドを展開して表示
da=`date +%F`
cp $da.log{,.bak}
$ ./bkup.sh
++ date +%F
+ da=2010-05-28
+ cp 2010-05-28.log 2010-05-28.log.bak
このバックアップスクリプトでは、当日の日付が付いたログファイルを .bak 拡張子付きでコピーしています。波括弧内の最初の要素が空であるため、最初の要素にはプレアンブルのみが適用されます。
2. ブレース展開を使ったリストアの例
$ cat restore.sh
set -x # コマンドを展開して表示
da=`date +%F`
cp $da.log{.bak}
$ ./restore.sh
++ date +%F
+ da=2010-05-28
+ cp 2010-05-28.log.bak 2010-05-28.log
リストアスクリプトでは、パラメータの最初の要素が .bak で、2番目の要素が空になっています。これにより、バックアップファイルを元のファイル名へ戻すことができます。
Bashシェル関数については、以前の記事もあわせて参考にしてください。
3. プレアンブルとポストスクリプトなしのブレース展開の例
プレアンブルとポストスクリプトを指定しない場合は、波括弧内の要素がそのまま展開されます。
$ cat expand.sh
echo {oct,hex,dec,bin}
$ ./expand.sh
oct hex dec bin
オプションのプレアンブルやポストスクリプトがない場合、結果は指定した文字列がスペースで区切られたリストになります。
範囲指定のブレース展開
ブレース展開では、シーケンス(連続した値)も展開できます。シーケンスには整数または文字を使用できます。
4. 整数と文字のシーケンスの例
$ cat sequence.sh
cat /var/log/messages.{1..3}
echo {a..f}{1..9}.txt
$ ./sequence.sh
May 9 01:18:29 x3 ntpd[2413]: time reset -0.132703 s
May 9 01:22:38 x3 ntpd[2413]: synchronized to LOCAL(0), stratum 10
May 9 01:23:44 x3 ntpd[2413]: synchronized to
May 9 01:47:48 x3 dhclient: DHCPREQUEST on eth0
May 9 01:47:48 x3 dhclient: DHCPACK from 23.42.38.201
..
..
a1.txt a2.txt a3.txt a4.txt b1.txt b2.txt b3.txt b4.txt c1.txt c2.txt c3.txt c4.txt
最初のcatコマンドでは、messages.1、messages.2、messages.3 に展開され、それぞれの内容が表示されます。次のecho文では、文字シーケンスと整数シーケンスを組み合わせて使用しています。
増分値を指定したシーケンス
kshのブレース展開では、増分値(increment)を指定してシーケンスを生成できます(Bashでもバージョン4.0以降は同じ構文が利用可能です)。
構文: <start>..<end>..<incr>
incrは数値です。負の整数も使用できますが、符号はstartとendの順序から自動的に推測されます。
5. シーケンスで増分値を使う例
$ ksh
$ echo /var/log/messages.{1..7..2}
/var/log/messages.1 /var/log/messages.3 /var/log/messages.5 /var/log/messages.7
$
この方法を使えば、隔日のログファイルだけを抽出して確認するといったことも簡単に行えます。
ブレース展開の落とし穴
ブレース展開ではBashの変数は展開されません。これは、ブレース展開がシェル展開の最初のステップとして実行され、変数の展開はその後の段階で行われるためです。変数を使いたい場合は、evalコマンドなどを併用する回避策が必要になります。
6. 展開内で変数を使った例
以下の2つのfor文の出力を見比べると、上述の落とし穴がよく分かります。
$ cat var_seq.sh
# シーケンスを使って1から4まで表示
for i in {1..4}
do
echo $i
done
start=1
end=4
# 変数を使って1から4まで表示
echo "変数で表現したシーケンス"
for i in {$start..$end}
do
echo $i
done
$ ./var_seq.sh
1
2
3
4
変数で表現したシーケンス
{1..4}
後半のfor文では {$start..$end} が展開されず、文字列 {1..4} がそのまま出力されている点に注目してください。日常的なシェル操作やスクリプト作成において、ブレース展開を正しく理解しておくことで、コマンド入力の手間を大幅に削減できます。
-
Bash変数チュートリアル – 基本からグローバル変数・ローカル変数まで学べる6つの実用例
Bash変数は、プログラムの実行期間中に必要となる情報を一時的に保存しておくための仕組みです。本記事はBashチュートリアルシリーズの一篇で、他のプログラミング言語と同様にBashでも変数を利用できることを踏まえ、基本的な使い方からグローバル変数とローカル変数の違いまでを、6つの実用的なサンプルを通じて解説します。 Bash変数の基本構文 変数の定義は非常にシンプルで、次の書式に従います。 VARNAME=VALUE 注意: 変数へ代入する際は、「=」記号の前後にスペースを入れてはいけません。「VAR=VALUE」のように書けば、シェルは「=」を代入記号として認識し、この行を変数への代入とし
-
実用的な5つの例で学ぶBashスクリプト入門チュートリアル
Unix SedやUnix Awkシリーズと同様に、本シリーズではBashスクリプティングに関する記事を複数回にわたって公開します。実用的なサンプルを交えながら、Bashスクリプティングのテクニックを幅広く解説していきます。 シェルとは、ユーザーが入力したコマンドを解釈して実行するプログラムです。コマンドはユーザーが直接入力するか、「シェルスクリプト」と呼ばれるファイルから読み込まれます。 ユーザーからの入力を直接読み取る場合、そのシェルは対話型(インタラクティブ)シェルと呼ばれます。 一方、ファイルからコマンドを読み込んで実行する場合は非対話型(ノンインタラクティブ)シェルと呼ばれます。この