LinuC入門|Linuxのワイルドカードとブレース展開の使い方

ファイル名の規則を味方につけて、Linuxの操作をすばやく正確に進めよう。

Linuxで複数のファイルを扱うとき、すべてのファイル名を一つずつ入力するのは大変です。ファイルの数が増えるほど入力に時間がかかり、タイプミスも発生しやすくなります。

そこで役立つのが、ワイルドカードとブレース展開です。

ワイルドカードを使うと、ファイル名の一部をパターンとして指定し、そのパターンに一致する既存のファイルをまとめて選択できます。一方、ブレース展開を使うと、複数の文字列や連続した番号を効率よく生成できます。

たとえば、次のような操作を簡潔に記述できるようになります。

  • 拡張子が.txtのファイルをまとめて表示する
  • ファイル名の特定の位置に1文字だけ含まれるファイルを探す
  • 数字を含むファイルだけを選択する
  • 数字を含まないファイルだけを選択する
  • 連番が付いた複数のファイルを一度に作成する
  • 用途別の名前を持つファイルをまとめて作成する

この記事では、AlmaLinux 10.2のBash環境を使用し、lsとtouchによる実例を交えながら、ワイルドカードとブレース展開の違いや使い分けを詳しく解説します。

ワイルドカードとは

ワイルドカードは、ファイル名やディレクトリ名の一部を特殊文字に置き換え、複数の名前をパターンで指定する仕組みです。

代表的なワイルドカードとブレース展開の形式は、次のとおりです。

形式意味指定例
*任意の文字列に一致する。0文字でもよい*.txt
?任意の1文字に一致するreport?.txt
[文字]角括弧内に書かれたいずれか1文字に一致するreport[13a].txt
[開始-終了]指定した範囲内の1文字に一致するreport[1-4].txt
[^文字]角括弧内に書かれていない1文字に一致するreport[^ab].txt
[^開始-終了]指定した範囲に含まれない1文字に一致するreport[^0-9].txt
{文字列,文字列}カンマで区切った文字列を生成するconfig{dev,prod}.txt
{開始..終了}連続する数値や文字を生成するlog{1..5}.txt

*、?、[...]は、既存のファイル名を探すためのワイルドカードです。

{...}はワイルドカードではなく、指定された規則に従って文字列を生成するブレース展開です。

両者の違いを整理すると、次のようになります。

機能主な役割ファイルの存在
ワイルドカードパターンに一致する名前を探す基本的に既存の名前が対象
ブレース展開規則に従って複数の文字列を生成するファイルが存在しなくても展開される

ワイルドカードを展開するのはBash

ls .txtを実行したとき、.txtを直接解釈しているのはlsではありません。

AlmaLinuxの端末で使用されるBashが、先にカレントディレクトリを調べます。そして、*.txtに一致する既存のファイル名を見つけ、その名前へ置き換えてからlsを実行します。

たとえば、カレントディレクトリに次のファイルが存在するとします。

memo.txt
report1.txt
report2.txt
report12.txt

この状態で、次のように実行します。

suzuki@AlmaLinux:~$ ls report?.txt
report1.txt  report2.txt

内部では、おおむね次の順序で処理されています。

入力した内容
ls report?.txt

Bashによる展開
ls report1.txt report2.txt

lsが受け取る内容
report1.txtとreport2.txt

?は任意の1文字に一致します。そのため、report1.txtとreport2.txtは対象になりますが、report12.txtは対象になりません。

図1:ワイルドカードが展開されるまでの流れ

この図から分かること

ワイルドカードを既存のファイル名へ展開するのは、lsではなくBashです。

Bashがreport?.txtに一致するファイルを探し、見つかったファイル名をlsへ渡します。lsは、Bashから受け取ったファイル名を表示します。

?が表すのは1文字だけです。そのため、reportの後ろに数字が2文字あるreport12.txtは対象外になります。

練習用ファイルをブレース展開で作成する

ワイルドカードの動きを確認できるように、練習用のファイルを用意しましょう。

ファイル名を一つずつ入力しても作成できますが、ここでは少ない入力で複数の名前を生成できるブレース展開を利用します。

touchコマンドとは

touchは、指定したファイルのタイムスタンプを更新するコマンドです。

指定したファイルが存在しない場合は、中身が空の新しいファイルを作成します。この性質を利用すると、ワイルドカードの練習に必要なファイルを簡単に用意できます。

touchコマンドの書式
touch [オプション] ファイル...

ファイルには、タイムスタンプを更新するファイル、または新しく作成するファイルの名前を指定します。

末尾の...は、複数のファイルを指定できることを表しています。実際のコマンド入力では、...を入力する必要はありません。

touchコマンドで使用する主なオプション

今回の操作では、touchにオプションを指定しません。

オプション説明
なし指定したファイルのタイムスタンプを更新する。ファイルが存在しない場合は空のファイルを作成する

次のコマンドを実行して、練習用ファイルを作成します。

suzuki@AlmaLinux:~$ touch report{1,2,3,4,a,b,12,21}.txt
suzuki@AlmaLinux:~$ touch {memo,notes,guide}.txt
suzuki@AlmaLinux:~$ touch log{1..5}.txt

1行目では、reportと.txtの間に入れる文字列を波括弧内に指定しています。

report1.txt
report2.txt
report3.txt
report4.txt
reporta.txt
reportb.txt
report12.txt
report21.txt

2行目では、次の3個のファイル名が生成されます。

memo.txt
notes.txt
guide.txt

3行目の{1..5}は、1から5までの連続した数値へ展開されます。

log1.txt
log2.txt
log3.txt
log4.txt
log5.txt

{1..5}から生成されるのは、1、2、3、4、5です。負の数は含まれません。

lsコマンドで作成結果を確認する

lsは、ファイルやディレクトリの名前や情報を表示するコマンドです。

引数にワイルドカードを含むパターンを指定すると、Bashによって展開されたファイルをまとめて確認できます。

lsコマンドの書式

ls [オプション] [ファイルまたはディレクトリ...]

ファイルまたはディレクトリを省略すると、カレントディレクトリの内容が表示されます。

作成したテキストファイルを確認してみましょう。

suzuki@AlmaLinux:~$ ls *.txt
guide.txt  log1.txt  log2.txt  log3.txt  log4.txt  log5.txt
memo.txt   notes.txt report1.txt report2.txt report3.txt
report4.txt report12.txt report21.txt reporta.txt reportb.txt

実際の表示順や1行に並ぶファイル数は、端末の幅やロケールなどによって変わることがあります。

*で任意の文字列を指定する

*は、その位置にある0文字以上の任意の文字列と一致します。

次の指定では、ファイル名の末尾が.txtになっている既存ファイルが対象です。

suzuki@AlmaLinux:~$ ls *.txt
guide.txt  log1.txt  log2.txt  log3.txt  log4.txt  log5.txt
memo.txt   notes.txt report1.txt report2.txt report3.txt
report4.txt report12.txt report21.txt reporta.txt reportb.txt

*.txtは、次のように読み取れます。

  • *は、ファイル名の先頭から.txtの直前までにある任意の文字列
  • .txtは、ファイル名の末尾に必要な固定文字列

ファイル名がreportで始まり、.txtで終わるファイルに絞り込む場合は、次のように指定します。

suzuki@AlmaLinux:~$ ls report*.txt
report1.txt  report2.txt  report3.txt  report4.txt
report12.txt report21.txt reporta.txt  reportb.txt

reportと.txtの間には、1文字でも複数文字でも入ることができます。

このため、report1.txtだけでなく、report12.txtやreport21.txtも対象になります。

*は0文字以上を表すため、report.txtが存在する場合は、そのファイルもreport*.txtに一致します。

?で任意の1文字を指定する

?は、その位置にある任意の1文字と一致します。0文字や2文字以上には一致しません。

suzuki@AlmaLinux:~$ ls report?.txt
report1.txt  report2.txt  report3.txt  report4.txt
reporta.txt  reportb.txt

このパターンでは、reportの直後に1文字だけあり、その後ろに.txtが続くファイルが対象です。

ファイル名一致するか理由
report1.txt一致するreportの後ろが1文字
reporta.txt一致する英字も任意の1文字として扱われる
report12.txt一致しないreportの後ろが2文字
report.txt一致しないreportの後ろに文字がない

ファイル名の長さを限定したいときは、*よりも?が適しています。

[...]で候補となる1文字を指定する

角括弧を使うと、その位置に入る1文字の候補を指定できます。

次の例では、1、3、aのいずれか1文字が入るファイルを表示します。

suzuki@AlmaLinux:~$ ls report[13a].txt
report1.txt  report3.txt  reporta.txt

[13a]全体が1文字分の条件です。13aという3文字の並びを指定しているわけではありません。

パターン一致する1文字
[13a]1、3、aのいずれか
[abc]a、b、cのいずれか
[246]2、4、6のいずれか

report12.txtは、reportの後ろに2文字あるため、report[13a].txtには一致しません。

[開始-終了]で文字の範囲を指定する

角括弧内でハイフンを使うと、連続する文字の範囲を指定できます。

suzuki@AlmaLinux:~$ ls report[1-4].txt
report1.txt  report2.txt  report3.txt  report4.txt

[1-4]は、1から4までのいずれか1文字に一致します。

ここでも、角括弧が表すのは1文字だけです。このため、report12.txtやreport21.txtは対象になりません。

0から9までの数字1文字を指定する場合は、次のように実行します。

suzuki@AlmaLinux:~$ ls report[0-9].txt
report1.txt  report2.txt  report3.txt  report4.txt

[0-9]は、数字以外を指定する書き方ではありません。0から9までの数字1文字を指定する書き方です。

そのため、reporta.txtやreportb.txtは対象になりません。

[^...]で含まれない文字を指定する

角括弧内の先頭に^を置くと、指定した文字や範囲に含まれない1文字を表せます。

数字以外の1文字が入るファイルを確認してみましょう。

suzuki@AlmaLinux:~$ ls report[^0-9].txt
reporta.txt  reportb.txt

このパターンは、次のように解釈できます。

report      固定文字列
[^0-9]     0から9に含まれない任意の1文字
.txt        固定文字列

reporta.txtとreportb.txtは、該当する位置の文字が数字ではないため一致します。

一方、次のファイルは対象外です。

  • report1.txtは、該当する位置が数字
  • report12.txtは、reportの後ろが2文字
  • report.txtは、該当する位置に文字がない

^は、角括弧内の先頭に置いた場合に否定の意味を持ちます。先頭以外に置いた場合は、通常の文字として扱われることがあります。

図2:ワイルドカードごとの一致範囲

この図から分かること

*は文字数を限定せず、?と[...]は1文字分の条件になります。

そのため、report12.txtはreport*.txtには一致しますが、report?.txtやreport[1-4].txtには一致しません。

また、report[^0-9].txtを使えば、指定した位置が数字ではないファイルを選択できます。同じファイル名でも、使用するワイルドカードによって対象になるかどうかが変わります。

ブレース展開とは

ブレース展開は、波括弧の中に指定した文字列や連続値から、複数の文字列を生成するBashの機能です。

ワイルドカードのように既存ファイルを検索するのではなく、書かれた規則に従って文字列を機械的に作ります。

たとえば、config{dev,test,prod}.txtは、次の3つの文字列へ展開されます。

configdev.txt
configtest.txt
configprod.txt

この時点では、それぞれの名前を持つファイルが存在するかどうかは確認されません。

カンマで複数の文字列を展開する

カンマで区切った文字列を波括弧の中に記述すると、それぞれの文字列を使った名前が生成されます。

suzuki@AlmaLinux:~$ touch config{dev,test,prod}.txt

Bashによる展開後の内容は、次のようになります。

touch configdev.txt configtest.txt configprod.txt

作成結果をlsで確認します。

suzuki@AlmaLinux:~$ ls config{dev,test,prod}.txt
configdev.txt  configtest.txt  configprod.txt

共通部分であるconfigと.txtを一度だけ入力できるため、似た名前のファイルを複数指定するときに便利です。

連続した数値を展開する

2つのドットで開始値と終了値をつなぐと、連続する数値を生成できます。

suzuki@AlmaLinux:~$ touch day{1..5}.txt

展開されるファイル名は、次のとおりです。

day1.txt
day2.txt
day3.txt
day4.txt
day5.txt

作成結果を確認します。

suzuki@AlmaLinux:~$ ls day{1..5}.txt
day1.txt  day2.txt  day3.txt  day4.txt  day5.txt

開始値と終了値の両方が範囲に含まれます。

{1..5}を指定した場合は、1から5までが生成されます。-1から5までが生成されるわけではありません。

桁数をそろえた連番を作る

開始値または終了値を0で始めると、数値の桁数をそろえて展開できます。

suzuki@AlmaLinux:~$ touch backup{01..05}.txt

作成されるファイルは、次のとおりです。

backup01.txt
backup02.txt
backup03.txt
backup04.txt
backup05.txt

lsで確認してみましょう。

suzuki@AlmaLinux:~$ ls backup{01..05}.txt
backup01.txt  backup02.txt  backup03.txt  backup04.txt  backup05.txt

連番の桁数をそろえると、ファイル名を並べたときに番号の順序を把握しやすくなります。

連続した英字を展開する

ブレース展開では、数値だけでなく連続する英字も生成できます。

suzuki@AlmaLinux:~$ touch node{a..c}.txt

このコマンドでは、次の3つのファイル名が生成されます。

nodea.txt
nodeb.txt
nodec.txt

作成結果はlsで確認できます。

suzuki@AlmaLinux:~$ ls node{a..c}.txt
nodea.txt  nodeb.txt  nodec.txt

同じ規則のファイル名をまとめて指定したいときに活用できます。

ワイルドカードとブレース展開を組み合わせる

Bashでは、ブレース展開が先に実行され、その後にワイルドカードによるファイル名展開が行われます。

次のコマンドを見てみましょう。

suzuki@AlmaLinux:~$ ls report{1,2}*.txt
report1.txt  report12.txt  report2.txt  report21.txt

最初にブレース展開が行われ、次の2つのパターンが生成されます。

report1*.txt
report2*.txt

続いて、それぞれの*が既存のファイル名へ展開されます。

report1*.txt
  report1.txt
  report12.txt

report2*.txt
  report2.txt
  report21.txt

最後に、展開された4つのファイル名がlsへ渡されます。

処理順入力または展開結果
1. コマンドを入力ls report{1,2}*.txt
2. ブレース展開ls report1*.txt report2*.txt
3. ワイルドカード展開ls report1.txt report12.txt report2.txt report21.txt
4. lsを実行4つのファイル名を表示

図3:ブレース展開とワイルドカードの処理順

この図から分かること

波括弧とワイルドカードを同じ指定に含めた場合、Bashは最初にブレース展開を行います。その後、生成された各文字列に含まれるワイルドカードを既存のファイル名へ展開します。

report{1,2}.txtでは、まずreport1.txtとreport2*.txtが生成されます。その後、それぞれのパターンに一致する既存ファイルが探されます。

処理される順番を理解しておくと、複数の条件を組み合わせたときにも、どのファイルが対象になるのかを予測しやすくなります。

一致するファイルがない場合

通常のBash環境では、ワイルドカードに一致するファイルが存在しない場合、パターンはファイル名へ置き換えられず、そのままコマンドへ渡されます。

たとえば、archiveで始まるテキストファイルが存在しない状態で、次のように実行したとします。

suzuki@AlmaLinux:~$ ls archive*.txt
ls: archive*.txt にアクセスできません: そのようなファイルやディレクトリはありません

Bashはarchive*.txtを既存のファイル名へ置き換えられないため、その文字列をそのままlsへ渡します。

lsはarchive*.txtという名前のファイルを表示しようとしますが、そのようなファイルが存在しないためエラーになります。

Bashの設定によっては、一致しないパターンの扱いが変わる場合がありますが、通常の初期設定では、展開されなかったパターンがそのまま残ると考えておくとよいでしょう。

ドットファイルとワイルドカードの関係

Linuxでは、名前がドットで始まるファイルは隠しファイルとして扱われます。

たとえば、次のようなファイル名です。

.settings.txt
.profile.txt

通常、*.txtのように先頭がドットではないパターンは、ドットで始まるファイル名には一致しません。

suzuki@AlmaLinux:~$ ls *.txt

この指定では、.settings.txtや.profile.txtは通常表示されません。

ドットで始まるテキストファイルを対象にする場合は、パターン側でも先頭のドットを明示します。

suzuki@AlmaLinux:~$ ls .*.txt
.profile.txt  .settings.txt

先頭のドットもファイル名の一部です。隠しファイルを含めたい場合は、パターンでドットを明示する必要があります。

パターンを指定するときの注意点

ワイルドカードとブレース展開は便利ですが、指定方法によっては想定より多くのファイルが対象になります。

特に*は、0文字以上の任意の文字列に一致するため、対象範囲が広くなりやすいワイルドカードです。

利用するときは、次の点を確認しましょう。

  • *は1文字だけでなく、複数文字にも一致する
  • *は0文字にも一致する
  • ?と[...]が表すのは1文字分の条件
  • [0-9]は数字以外ではなく、数字1文字を指定する
  • 数字以外を指定する場合は[^0-9]を使用する
  • {1..5}は1から5までを生成する
  • ブレース展開は既存ファイルを検索せず、指定された文字列を生成する
  • ブレース展開はワイルドカードによるファイル名展開より先に行われる
  • 通常の*では、名前がドットで始まる隠しファイルは対象にならない
  • touchにブレース展開を指定すると、展開されたすべての名前が処理対象になる

複雑なパターンを使用するときは、まずlsで対象を確認すると安心です。

suzuki@AlmaLinux:~$ ls report{1,2}*.txt
report1.txt  report12.txt  report2.txt  report21.txt

ここで表示されたファイルが想定どおりなら、パターンの展開結果を正しく把握できています。

ワイルドカードを見たときは既存ファイルを検索するもの、ブレース展開を見たときは文字列を生成するものと考えると、両者を区別しやすくなります。