グロブ(ワイルドカード)入門 - * ? [] と extglob の使い分け
この記事でできるようになること
- `*` `?` `[]` の 3 つの基本記号を使い分けられる
- グロブを展開しているのがシェルであることを説明できる
- 無マッチ時の挙動・隠しファイル・クォートの落とし穴を避けられる
前提知識(先に読むと理解しやすい記事)
この記事で学べること
- グロブ(ワイルドカード) が「シェル入力したコマンドを解釈してコンピュータに実行させる対話プログラム。の仕事」だと理解できます
*?[]の 3 つの基本記号 を使い分けられます{}(ブレース展開)との違いがわかりますextglob・隠しファイル・無マッチ時の挙動まで 落とし穴を避けられます
言葉の整理(先に取りちがえを防ぎます)
- グロブ:ファイル名をまとめて指すための書き方です。「ワイルドカード」「パターン」も、ほぼ同じものを指す呼び方です。この記事では「グロブ」にそろえます。
- 正規表現:文字の中身をさがすための書き方です。
grepなどで使います。グロブとは別のしくみです。 記号が似ているので取りちがえやすい点に気をつけてください。 - 展開:あなたが書いた記号を、シェルがほんもののファイル名に置きかえることです。
- 隠しファイル:名前が
.で始まるファイルです。.bashrcが代表例です。
* はグロブでは「何文字でも」という意味です。正規表現では「すぐ前の文字のくりかえし」という意味になります。同じ記号でも意味がちがいます。
結論(先に覚えるべき型)
- どんな文字が何個でも →
*(例:*.txt) - ちょうど1文字 →
?(例:file?.log) - 限られた候補から1文字 →
[](例:img[0-9].png) - 展開するのは コマンドではなくシェル
1. グロブとは何か?
結論: グロブはシェルがコマンド実行前にワイルドカードをファイル名へ展開する仕組み。コマンドは展開後の結果を受け取る。
ls *.txt と書くと .txt のファイルだけ出ますよね。あの * はどういう意味なのでしょうか。* は「どんな文字でも、何個でもよい」という意味の記号だよ。* を処理しているのが ls ではなくシェル だということ。ls ではないのですか。*.txt を見る。そして 実際に存在するファイル名に書きかえてから ls に渡すんだ。これをグロブ展開と呼ぶよ。展開のイメージ
カレントディレクトリに a.txt b.txt memo.md がある場合:
あなたが入力: ls *.txt シェルが展開: ls a.txt b.txt ← memo.md は外れる ls が受け取る: a.txt b.txt
ls は * を一切知らない。展開済みのファイル名を受け取るだけ。
グロブはファイル名のためのしくみです。文字の中身をさがす正規表現とは 別のもの です。grep で使う .* などが正規表現にあたります。取りちがえないでください。
先に、事故をふせぐ話
グロブは rm と組み合わせると強力です。同時にあぶなくもあります。rm で消したファイルは、GUI とちがってゴミ箱に行きません。その場ですぐ完全に消えます。
そこで、rm の前に同じパターンを ls で確かめるくせをつけてください。
$ ls *.tmp # まず何が対象になるかを目で見て確かめる $ rm *.tmp # 納得してから消す
本サイトの仮想ターミナルは学習用です。何を打っても、あなたのパソコンのファイルは消えません。安心して試してください。
2. * アスタリスク:0文字以上の任意の文字列
結論:
*は0文字以上の任意の文字列にマッチする。ただし先頭のドットとスラッシュにはマッチしない。
$ ls
a.txt b.txt data.csv report.txt notes.md
# 拡張子が .txt のものだけ $ ls *.txt
a.txt b.txt report.txt
*.txt は「何か + .txt」ということですね。* は 0 文字でもマッチする のもポイントだよ。だから * だけ書くと「全部」になる。re* はどうなりますか。report.txt がマッチする。* は前でも後ろでも真ん中でも置けるよ。# re で始まる $ ls re* report.txt # data を含む(前後に何かあってもOK) $ ls *data*
data.csv
* は 先頭のドットにマッチしません。 つまり隠しファイルは対象外です。
ls * を実行しても .bashrc のような隠しファイルは出てきません。これは rm * で設定ファイルまで巻きこんで消す事故をふせぐための決まりです。
3. ? クエスチョンマーク:任意の1文字
結論:
?はちょうど1文字にマッチする。文字数が決まっているファイルを狙うときに使う。
$ ls
log1.txt log10.txt log2.txt log3.txt
# log + 1文字 + .txt(log10.txt は2文字なので外れる) $ ls log?.txt
log1.txt log2.txt log3.txt
? は 1 文字だけなんですね。log10.txt が外れたのはなぜでしょうか。log?.txt は「log のあとに きっかり 1 文字、そして .txt」という意味だからだよ。log10.txt は 1 と 0 で 2 文字ある。だからマッチしないんだ。?? と 2 個並べればいい。log??.txt なら log10.txt がマッチするよ。# 2文字ぶん $ ls log??.txt
log10.txt
4. [] 角カッコ:候補の中から1文字
結論:
[]は角カッコ内に並べた文字のどれか1文字にマッチする。範囲指定や否定もできる。
$ ls
img0.png img1.png img2.png img9.png imgA.png
4-1. 候補を列挙する
# 0 か 1 か 2 のどれか $ ls img[012].png
img0.png img1.png img2.png
4-2. 範囲で指定する
# 0〜9 の数字1文字 $ ls img[0-9].png
img0.png img1.png img2.png img9.png
[0-9] で「0 から 9 まで」なんですね。アルファベットも指定できますか。[a-z] で小文字、[A-Z] で大文字だね。[a-zA-Z0-9] のように 組み合わせる こともできる。4-3. 否定する(! または ^)
# 数字「以外」の1文字 $ ls img[!0-9].png
imgA.png
[] の書き方まとめ
| 書き方 | 意味 |
|---|---|
[abc] |
a / b / c のどれか1文字 |
[a-z] |
a〜z の1文字(範囲) |
[0-9] |
0〜9 の1文字(範囲) |
[!0-9] |
数字以外の1文字(否定) |
[a-zA-Z] |
英字1文字(範囲の組合せ) |
5. {} ブレース展開:グロブと混同しやすい別物
結論: ブレース展開はファイルの有無に関係なく文字列を生成する。実在ファイルに展開するグロブとは別の仕組み。
# ブレース展開:3つの文字列を生成する
$ echo file{1,2,3}.txtfile1.txt file2.txt file3.txt
{} は文字列を作るだけで、ファイルが実在するかどうかは見ていない。{} は「これからまとめて作る」用途。* や [] は「すでにあるものを選ぶ」用途だと覚えるといいよ。# 連番ディレクトリをまとめて作る(実在しなくてOK)
$ mkdir log{2024,2025,2026}
# 連番の範囲も書ける
$ echo {1..5}1 2 3 4 5
* や [] は、あてはまるファイルが 1 つも無いとき はパターンがそのまま文字として残ります。これが bash のはじめの設定での動きです。
いっぽう {} はいつでも展開されます。動きがちがうので気をつけてください。
6. extglob:拡張グロブでもっと柔軟に
結論: extglob を有効にすると「いずれか」「除外」などの高度なパターンが書ける。既定では無効なので shopt で有効化する。
# 拡張グロブを有効化(bash) $ shopt -s extglob
@(...) で「いずれか」、!(...) で「除外」が書けるんだ。extglob の記法
| 書き方 | 意味 |
|---|---|
?(pattern) |
0回か1回 |
*(pattern) |
0回以上 |
+(pattern) |
1回以上 |
@(pattern) |
ちょうど1回(いずれか) |
!(pattern) |
pattern 以外 |
pattern の部分は | で区切って複数指定できます。
# .jpg または .png にマッチ $ ls *.@(jpg|png) # .txt 以外のすべて $ ls !(*.txt)
shopt -s extglob は、そのシェルだけの設定です。ターミナルを閉じるともとに戻ります。
今すぐもとに戻したいときは shopt -u extglob を実行します。
いつでも使いたいときは ~/.bashrc に書き足します。設定ファイルを触るので、先にコピーを取ってください。
$ cp ~/.bashrc ~/.bashrc.bak $ echo 'shopt -s extglob' >> ~/.bashrc $ source ~/.bashrc
おかしくなったら cp ~/.bashrc.bak ~/.bashrc で戻せます。>> は末尾に書き足す記号です。> は中身を全部消すので使いません。
7. よくある初心者のつまずき
結論: 無マッチ時の挙動・隠しファイル・クォートの3点が定番の落とし穴。仕様を知れば事故は防げる。
7-1. リナの失敗:マッチしないとパターンがそのまま残る
# .xml ファイルが1つも無い場合 $ ls *.xml
ls: '*.xml' にアクセスできません: そのようなファイルやディレクトリはありません
*.xml がそのまま出ています。* が効いていないのでしょうか。ls は「*.xml という名前のファイルが無い」と答えたんだ。shopt -s nullglob を使えば、0 件のときは何も渡さない動きに変えられるよ。7-2. 隠しファイルは * で拾えない
# 隠しファイルも対象にしたいとき $ shopt -s dotglob $ ls *
dotglob を有効にすると、* が隠しファイルにもあてはまります。ふだんは無効のままにしておくほうが安全です。
7-3. クォートするとグロブは無効になる
# クォートすると * は展開されない $ ls "*.txt"
ls: '*.txt' にアクセスできません: そのようなファイルやディレクトリはありません
"*.txt" や '*.txt' のように クォート文字列を引用符(' や ")で囲むこと。スペースなどを含む値をひとまとまりとして扱える。で囲むと、グロブ展開は起きません。
* を文字そのものとして使いたいときには便利です。ただし展開したいのに囲ってしまうと、思わぬところで無効になります。
8. ミニ課題:実際にやってみよう
結論: 拡張子の抽出・文字数指定・範囲指定の3問で、グロブの基本記号を手を動かして確かめる。
練習用のからっぽのディレクトリファイルをまとめて整理する入れ物。Windows や macOS の「フォルダ」と同じもの。を作り、その中で試します。こうすれば、もとからあるファイルにはふれません。
# 練習用ディレクトリとファイルを準備 $ mkdir -p ~/glob-practice && cd ~/glob-practice $ touch a.txt b.txt c.log data1.csv data2.csv data10.csv
課題 1: .csv で終わるファイルだけを一覧表示しよう。
ヒント 1(方向づけ)を見る
「名前のはじめは何でもよい。ただし終わりは .csv」と伝えます。はじめの部分にあたる記号を 1 つ使います。
ヒント 2(コマンド名)を見る
一覧を出すのは ls です。「何文字でもよい」を表す記号は * です。
答えを見る
$ ls *.csv
data1.csv data10.csv data2.csv
.csv で終わる 3 つが出ます。a.txt や c.log は外れます。
なお ls は名前を文字として並べます。そのため data10.csv が data2.csv より先に出ます。
課題 2: data + 1 文字 + .csv のファイルだけを表示しよう。data10.csv は除きます。
ヒント 1(方向づけ)を見る
今度は文字の数を決めます。「何文字でもよい」ではなく「ちょうど 1 文字」を表す記号を使います。
ヒント 2(コマンド名)を見る
一覧を出すのは ls です。ちょうど 1 文字を表す記号は ? です。
答えを見る
$ ls data?.csv
data1.csv data2.csv
data10.csv は 1 と 0 で 2 文字あるので外れます。
課題 3: data1.csv と data2.csv だけを、角カッコを使って表示しよう。
ヒント 1(方向づけ)を見る
えらびたい文字を自分で並べます。「この中のどれか 1 文字」を表す書き方を使います。
ヒント 2(コマンド名)を見る
一覧を出すのは ls です。文字を並べるのは [] です。中に 1 と 2 を書きます。
答えを見る
$ ls data[12].csv
data1.csv data2.csv
[12] は「1 か 2 のどちらか 1 文字」という意味です。data10.csv は外れます。
練習が終わったら、作ったディレクトリごと片づけられます。
-r は「ディレクトリの中身ごと消す」というオプションです。-i を足すと、1 つずつ確認しながら消せます。まず ls で中身を目で見てから消してください。
$ cd ~ $ ls ~/glob-practice $ rm -ri ~/glob-practice
9. 振り返り
* は何文字でも、? はちょうど 1 文字、[] は並べた中から 1 文字。ここまで覚えました。rm と組み合わせるときは、先に同じパターンを ls で確かめること。それだけは忘れないで。今日の 3 行まとめ
- グロブを展開しているのはコマンドではなくシェル。コマンドは展開されたあとの名前を受け取る
*は 0 文字以上、?はちょうど 1 文字、[]は並べた中から 1 文字にあてはまるrmと組み合わせる前に、同じパターンをlsで確かめる