【bash】シェルにおけるパス名展開「*」「?」

ワイルドカードはよく使いますが、便利なものというのは強力すぎるので正しく扱えるように改めて確認します。


パス名展開

パス名展開は複数ファイルが存在するとき、その中にある一定の規則のファイル名を持つファイル(たとえば、末尾が".txt"の拡張子がついたファイルなど)を一括で引数として実行するときに利用します。


例えば、以下のような要素が詰まったディレクトリがあるとします。

$ ls -a
.        001.dat  004.dat  113.dat  333.dat  dir1
..       002.dat  111.dat  114.dat  444.dat  dir2
000.dat  003.dat  112.dat  222.dat  .dat     .txt

ここで dir1とdir2はディレクトリです。

今回はパス名展開で用いられる記号「*」について述べていきます。


「*」

よくワイルドカードと呼ばれています。

「*」は0文字以上の任意文字列に対応し、各ファイル名と照合して任意文字列に対応したパス名を0~9,a~zの順で展開します。


実際に確認します。

$ ls -a 
.        001.dat  004.dat  113.dat  333.dat  dir1
..       002.dat  111.dat  114.dat  444.dat  dir2
000.dat  003.dat  112.dat  222.dat  .dat     .txt


$ ls *
000.dat  002.dat  004.dat  112.dat  114.dat  333.dat
001.dat  003.dat  111.dat  113.dat  222.dat  444.dat

dir1:

dir2:


$ ls .*

.dat  .txt

.:
000.dat  003.dat  112.dat  222.dat  dir1
001.dat  004.dat  113.dat  333.dat  dir2
002.dat  111.dat  114.dat  444.dat

..:


$ ls -a
最初はディレクトリ内のものをすべてリストしました。


$ ls *
ここで分かるのは「*」のみでは「.」から始まるファイルの展開はできないという事です。
また、dir1/とdir2/は空のディレクトリなので中身はありません。

ちなみに、"ls -R"でほぼ同等(上位互換)の出力が可能です。


$ ls .*
先のことを踏まえ「*」の前に「.」をつけてリストしました。
これにより「.」から始まるファイルの展開ができました。
また、./と../も展開の対象となったため、相対パスディレクトリの中身もリストしています。




もうすこし細かく使っていきます。

$ ls -a 
.        001.dat  004.dat  113.dat  333.dat  dir1
..       002.dat  111.dat  114.dat  444.dat  dir2
000.dat  003.dat  112.dat  222.dat  .dat     .txt


$ ls *.dat
000.dat  002.dat  004.dat  112.dat  114.dat  333.dat
001.dat  003.dat  111.dat  113.dat  222.dat  444.dat


$ ls 0*.dat
000.dat  001.dat  002.dat  003.dat  004.dat


$ ls *1*.dat
001.dat  111.dat  112.dat  113.dat  114.dat


$ ls -a
省略


$ ls *.dat
ファイル名に「.dat」を含むファイルが展開・リストされます。


$ ls 00*.dat
頭に「0」、末尾に「.dat」が付くファイルが展開・リストされます。
「*」は0文字以上の任意文字列なので、"01, 02, 03, 04"が対応しています。


$ ls *1*.dat
「*」は複数同時に利用することも可能です。



最後はディレクトリを超えて使ってみます。

$ ls -R
.:
000.dat  003.dat  112.dat  222.dat  dir1
001.dat  004.dat  113.dat  333.dat  dir2
002.dat  111.dat  114.dat  444.dat

./dir1:

./dir2:


$ mv 1*.dat dir1/

$ mv 2*.dat dir2/

$ ls -R.dat
.:
000.dat  002.dat  004.dat  444.dat  dir2
001.dat  003.dat  333.dat  dir1

./dir1:
111.dat  112.dat  113.dat  114.dat

./dir2:
222.dat


$ ls */*2.dat
dir1/112.dat  dir2/222.dat


$ ls -R
ディレクトリの内容までリストしています。


$ mv 1*.dat dir1/
$ mv 1*.dat dir1/
「*」を用いてファイルの移動を行いました。


$ ls -R
各ファイルの位置を確認してます。


$ ls */*2.dat
ディレクトリの情報も含めてパス名展開しました。


「?」

「*」と合わせてワイルドカードと呼ばれます。

「?」は1文字の任意文字に対応し、各ファイル名と照合して任意文字に対応したパス名を0~9,a~zの順で展開します。

  • 「*」: 0文字以上の任意文字列
  • 「?」: 1文字の任意文字

「?」の方が制限が強めなことがわかります。


一応軽く利用してみます。

$ ls -a
.        001.dat  004.dat  113.dat  333.dat  dir1
..       002.dat  111.dat  114.dat  444.dat  dir2
000.dat  003.dat  112.dat  222.dat  .dat     .txt


$ ls ?1?.dat
111.dat  112.dat  113.dat  114.dat

「*」で十分確認できたはずなので、解説については省略します。


おわりに

パス名展開「*」「?」については以上です。
残りのパス名展開については別の記事で。

要らないファイルを一気に削除したりと便利ではあるのですが、
$ rm *.dat
として大事なデータもなくすリスクもあります。


このリスクを回避するため、rmに関する記事もそのうち書きたいです。