2-2 豊富なワイルド・カードでファイル名の入力が楽になる!

Keywords

ワイルド・カード,ファイル名置換


こんなことができる

 任意のコマンドの中で,類似したファイル名を一括して指定することができます。たとえば,C言語のソース・ファイル名は終わりが .c ですから,カレント・ディレクトリ中のそれらだけをリストアップするには,

% ls *.c

とします。また,3文字のファイル名だけを見たければ,

% ls ???

とすればOKです。さらに,頭文字が a , A , b , B のどれかで始まるもの,英大文字で始まるもの,というそれぞれの条件の場合には,

% ls [aAbB]*
% ls [A-Z]*

というようにすればできます。


こうすればできる

 ここで登場した, * , ? , [ , ] の各特殊文字は,「ワイルド・カード(文字)」と呼ばれ,任意のコマンド中でファイル名を指定するときに利用できます。

各文字の意味は次のとおりです。

文字 意味
* 任意の文字列の代わりになる。文字列の長さは0でもよい。
? 任意の1文字の代わりになる。
[] かぎ括弧の中に記述した任意の1文字の代わりになる。連続する文字コードの指定には - 記号が使える。たとえば, [a-c] は [abc] と同じ意味.

 これらはいくつでも自由に組み合わせて使えます。たとえば次のファイル指定の意味は「頭文字が英大文字で, file という文字を含み, _ か . の次に任意の1文字で終わる」ということになります。

[A-Z]*file*[_.]?

このような指定は一見面倒にみえますが,慣れるとそれほどでもなく,後述のようにファイルの管理を行う場合に威力を発揮します。


背景

 MS-DOSでは,ワイルド・カード文字として, ? と * がありました。つまり, ? は任意の1文字, * は任意の文字列(長さが0以上)を表しますが,実際には次のような例ではうまくいかず,完全なワイルド・カード文字とはいえないのが現状です。

dir a*k.* ……k の指定が無視される.
dir ???.??? ……??? は3文字だけでなく,3文字以内を含んでしまう.
type ????.c …… エラーになる.

 この原因は,ワイルド・カード文字の展開をコマンド・プロセッサ( command.com )が行うのではなく,各コマンド(上の例では, dir や type コマンド)がそれぞれ独自に行っているためで,typeコマンドではまったく行わなかったり, dir での処理が不十分であるところに問題があります。

これに比べてUNIXの場合は,コマンド・プロセッサとしてのシェル(BシェルやCシェル)がすべて確実に展開してくれるため,任意のコマンドでワイルド・カードが共通に使えるわけです。したがって,自分でコマンドを作成する場合にも,ワイルド・カードに関する処理をプログラム中で行う必要がありません。


[ワイルド・カード対応のコマンド]

 ワイルド・カードはファイル名を指定するときに用いるため,ワイルド・カードはシェルによって「ファイル名置換がなされる」といいます。ファイル名置換が行われると通常複数個のファイル名に展開されますから,ファイルのハンドリングを行うコマンドを作成する際は,複数のファイル名を指定してもかまわないようにすべきです。この例を,mv と cpコマンドについて見てみることにします。

1章では cp と mv の基本的な使い方しか述べませんでしたが,ワイルド・カードを考慮して,次のような指定もできるようになっています。

% cp file1 file2 dir1 …… file1とfile2をdir1ディレクトリの下にコピー

 ここで, dir1 をディレクトリ名としますと, file1 , file2 の二つのファイルを dir1 ディレクトリ内にコピーできます。MS-DOSの copyコマンドでは,このような指定が許されていません。

 また,コピーするファイルの個数は問いませんから,次のようにワイルド・カードが使えます(これはMS-DOSでも可)。

% cp *.c dir …… Cのソース・ファイルすべてをdirディレクトリの下にコピー

 mvコマンドでも同様にできます。MS-DOSよりすごいのは,MS-DOSの renameコマンドがその名のとおり,ファイル名の変更しかできないのに対して, mvコマンドはその名前( mOvE の略)からもわかるように,ファイルを任意のディレクトリに移動できます。

% mv *.c dir …… Cのソース・ファイルすべてをdirディレクトリの下に移動

というコマンドは,カレント・ディレクトリのすべてのCのソース・ファイルをディレクトリ dir の下に移動します。このように,すでにあるファイル群を整理するときにワイルド・カードの実力が発揮できるように各コマンドが考慮されているわけです。

ところで,次のコマンドの意味がおわかりですか。

% rm * …… カレント・ディレクトリの下のファイルをすべて消せ!

 ワイルド・カードの*は任意の文字列を表しますから,カレント・ディレクトリのすべてのファイル(ただし,頭文字が . で始まるものを除く)を消去してしまうというきわめて危険なコマンドです。リターン・キーを押したが最後, rmコマンドは何の容赦もせずに,すべてのファイルを消してしまうでしょう。1文字のファイル名を指定するための ? のつもりが * とタイプミスしてしまったときは目も当てられません。

 このような場合に備えて, i オプションが用意されています。次の例のように,一つのファイルを消すたびに,確認のメッセージを出してくれますから,消していいときは y ,そうでないときは n を入れます。

% ls -C
atoi.c meibo.c rvsline.c test.c test0.c upper.c

% rm -i *
atoi.c: ? n …… 「消してはダメ!」
meibo.c: ? y …… 「消してください」
rvsline.c: ? n (以下同じ)
test.c: ? y
test0.c: ? y
upper.c: ? n

% ls -C
atoi.c rvsline.c upper.c
%

[Cシェル,BAシェルの追加機能]

 以上の話はシェルが何であろうと実行できるものでしたが,CシェルとBAシェルではもう二つのファイル置換のためのワイルド・カードが用意されています。一つは { } です。この例を次に示します。

% ls -C
d1.c d2.batch f1.exec p1.comm
% ls *.{exec,comm}
f1.exec p1.comm
%

 このように, { } の中には任意個の文字列をコンマで区切って指定できます。 [ ] では1文字ごとにしか指定できませんでしたが,これを文字列に拡張したわけです。

 もう一つのワイルド・カードは ~ 文字です。次の例のように, ~ は自分のホーム・ディレクトリに置換されます。つまり,ホーム・ディレクトリ中のCソース・ファイルをすべてカレント・ディレクトリ(行末の . で指定されている)にコピーしているわけです。

% cd dir1
% cp ~/*.c . ……ホーム・ディレクトリ下の全Cソース・ファイルをカレント・ディレ クトリ(dir1)下にコピー
このとき,

% cp ~fuwa/*.c .

というように, ~ の次に他人のログイン名をかくと,その人のホーム・ディレクトリが指定できます。グループでプログラム開発をするときなどは便利に使えるでしょう。


注意・アドバイス

MS-DOSではすべてのファイルの指定には, *.* というワイルド・カードを用いますね。これは,拡張子を意識しなければいけないからです。一方UNIXで, *.* とやると,ファイル名の中に . を含んでいるものということになってしまいます。UNIXでは特別な場合を除いて . 以降の拡張子は何の意味を持たないことに注意してください。

* はすべての文字列に対応しますが,実は唯一の例外があります。それは先頭の . です。たとえば, rm * とするとカレント・ディレクトリ上のすべてのファイルが消去されるといいましたが, .file などの . で始まるファイルは該当しません。これも含めて消すには, rm .* とします。
この例外の存在理由は, . がカレント・ディレクトリ, .. が親ディレクトリを意味するためです。もし, * が . や .. を包含してしまうと,上の例ではカレント・ディレクトリや親ディレクトリが消去されるという異常事態が発生してしまいます。

万が一,ワイルド・カード文字を含むファイル名をアクセスしなければならないときはどうすればよいでしょうか。たとえば * というファイルがあったとします(どのようにすればこんな名のファイルが作れるのでしょうか?)。

% ls -l
total 2
-rw------- 1 s002 other 29 Jan 25 17:09 *
-rw------- 1 s002 other 629 Jan 25 17:09 whofile
%

このファイルを消したいときに,まさか rm * とはできませんね。こんな場合は次のようにします。

% rm \*
% ls -l
total 1
-rw------- 1 s002 other 629 Jan 25 17:09 whofile
%

つまり,ワイルド・カード文字の直前に \ (システムによっては \(逆スラッシュ))をいれると,その文字自体を意味するようになっているため,ワイルド・カード文字としての意味はなくなるわけです。

上で登場した \ 文字はその用途として,次の三つがあります。
(1)メタキャラクタ(ワイルド・カード文字やリダイレクション関係の特殊文字など)として使用されている本来の字,そのものを引用するため。
(2)行を継続するため。
(3)改行やタブなど,印刷不可能な文字を明示するため。
(1)については上述しましたので,(2)の例をあげましょう。

% ls -l \ …… \ で行を継続( ls -l whofile と入力したのに同じ)
whofile
-rw------- 1 s002 other 37 Jan 24 20:20 whofile
%

コマンドを2行以上で入力したいときにはこのように改行の前に \ を入れます。なお,(3)の例は後で出てきます。

ワイルド・カードの展開は既存のファイルについてのみ行われます。次の例の *.c のように,これから生成しようとするファイル名としては利用しても無意味であることに注意してください。

% cp * *.c …… すべてのファイルに.cの拡張子をつけたいが,....
Usage: cp f1 f2 エラーとなる!
cp f1 ... fn d1 … エラー・メッセージ(こういう形式しか認めない!)
%

当然の話ですが,標準出力リダイレクト記号( > )の次には,1個のファイル名しか指定できません。したがって,次のようなワイルド・カード文字を指定しても展開されませんので注意してください。

% ls -l >*
*: Ambiguous. …… エラー・メッセージ(*ではあいまいだ!)
%

BシェルとBAシェルでは,ワイルド・カード文字の [ ] 内の先頭に ! を入れると,「その文字列以外の文字」という意味になります。

$ ls
a.c
b
datefile
whofile
$ ls [!ab]* …… a や b で始まらないすべてのファイル名
datefile
whofile
$

cp はファイルの複写を行うコマンドですから,ディスク容量の問題を別にすればワイルド・カードを用いて大量のファイルを間違ってコピーしてもさほど問題はありません。しかし,mv では元のファイルが消えてしまいますので,実行の前後は充分注意してください。
また,これらのコマンドに限らず,ワイルド・カードを用いるときは pwdコマンドでカレント・ディレクトリを確認するくせをつけると間違いが防げます。


システム管理者の仕事

特にありません。


コマンドマニュアル

新出のコマンドがありませんので,ファイル置換関連のワイルド・カードの一覧表を表に示します。

意味 Bシェル Cシェル
すべての文字列.長さ0のヌルストリングを含む * * *
任意の1文字 ? ? ?
文字列s中の1文字 [s] [s] [s]
文字列s中以外の1文字 [!s] 無し [!s]
文字列1または文字列2 無し {s1,s2} {s1,s2}
ホーム・ディレクトリ 無し ~/ ~/
ログイン名log_nameのホーム・ディレクトリ 無し ~log_name/ ~log_name/