この Linux ワイルドカードを間違って使用すると、データ損失の危険があります
Linux ワイルドカードを使用すると、ファイルのグループ全体に同時に作用する 1 つのコマンドを入力できます。問題がなければ、これは大幅な時間の節約になります。そしてそれができるのです。破壊的に。
ワイルドカードの用途
よく知られているワイルドカードは、疑問符 (?) とアスタリスク (*) です。これらはファイル名パターンの作成に使用できます。疑問符は任意の 1 文字を表し、アスタリスクはゼロ文字を含む任意の文字のシーケンスを表します。
これを知ることで、複数のファイル名に一致するパターンを構築できます。コマンドラインにすべてのファイル名を入力する代わりに、パターンを入力します。パターンに一致するすべてのファイルがコマンドによって処理されます。
次のようなディレクトリにファイルのコレクションがあるとします。
提供されたパターンに一致するファイルのグループを選択できます。
ls taf_*
これにより、名前の先頭に「taf_」が付いたすべてのファイルが得られます。
ls *.sh
ls s*.sh
最初のコマンドは、ディレクトリ内のすべてのシェル スクリプト ファイルを一覧表示します。 2 番目のコマンドは、シェル スクリプト ファイルでもある「s」で始まるファイルのみを一覧表示します。
それはすべて十分に簡単なことのように思えますが、ls ではそれが実現します。ただし、他のコマンドでもこのタイプのパターン マッチングを利用できます。コマンドが実行される前に、シェルがパターン マッチングによって支援しようとすると、問題が発生します。
find コマンドでのアスタリスクの使用
パターンを一致するファイルのリストに展開するアクションはグロビングと呼ばれます。
これは Unix バージョン 6 のスタンドアロン コマンドとして始まり、その後他のプログラムにリンクできるライブラリになり、現在ではシェルに組み込まれています。パターンの展開はシェルによって実行され、展開の結果はコマンド ライン パラメータとしてコマンドに渡されます。
find コマンドを使用した 2 つの例を見ていきます。 1 つは期待通りの結果をもたらしますが、2 つ目はおそらくあなたを驚かせるでしょう。
この例では、readme.txt という 1 つのファイルが含まれるディレクトリを使用します。 src と inc という 2 つのディレクトリがあります。これらには、C、H、MD、TMP ファイルが混在しています。
ls -R
find を使用すると、パターン (-name *.c) に一致する名前を持つファイル (-type f) を再帰的に検索でき、C ファイルのリストが得られます。
find . -type f -name *.c
-not オプションを追加すると、検索を逆にして、C ファイル以外のすべてを表示できます。
find . -type f -not -name *.c
このリストを確認した後、C ファイル以外のすべてを削除することにしました。これを行うには、-delete オプションを追加します。
find . -type f -not -name *.c -delete
find .
2 番目の find コマンドは、現在のディレクトリ内とその下のすべてを再帰的にリストします。残っているのは C ファイルだけです。
それは私たちのほとんどが予想していたとおりに機能しました。今度はまったく同じことを行いますが、今回は現在のディレクトリ内のファイルはテキスト ファイルではなく、C ファイルです。
ls -R
同じ find コマンドとオプションを使用して、C ファイル以外のすべてを削除します。それは私たちが望んでいたことではありません。
find . -type f -not -name *.c -delete
find .
これにより、現在のディレクトリにある 1 つの C ファイルを除いて、ディレクトリ ツリー内のファイルがすべて削除されます。
ファイルをもう一度リセットし、 使用想定されている方法でコマンドを発行します。
すべてのファイルは所定の位置にあり、前と同じように、現在のディレクトリに C ファイルがあります。
ls -R
今回は、ワイルドカード パターンを一重引用符で囲みます。
find . -type f -not -name '*.c' -delete
find .
それが私たちが望んでいたものです。 C ファイル以外はすべてバラバラになってしまいました。
OK、それで何が問題だったのでしょうか?
一重引用符は、シェルによるファイル名パターンの展開を停止します。コマンドが動作するために、そのままコマンドまたはプログラムに渡されます。
機能した例では、現在のディレクトリに readme.txt ファイルがありました。シェルは *.c に一致するものが見つからなかったため、*.c を渡して検索を実行しました。
C ファイル以外のすべてを削除した例では、現在のディレクトリに main.c というファイルがありました。シェルはパターンとそのファイルを照合し、ファイルの名前を find コマンドに渡しました。したがって、find の指示は、main.c と呼ばれないものをすべて削除するというものでした。
これを、ターミナル ウィンドウにコマンド ライン パラメータを表示するだけの小さな C プログラムで説明します。
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int i;
printf("You supplied %d arguments.\n", argc-1);
for (i=1; i<argc; i++)
printf("%-2d) \"%s\"\n", i, argv[i]);
exit (0);
}
これを glob.c というファイルとして保存し、次のようにコンパイルしました。
gcc -o glob glob.c
変数 argc は、プログラムに渡す引数の数を保持します。 for ループは引数のリストを実行し、それぞれの引数を端末ウィンドウに出力します。
for ループは、引数 0 ではなく、引数 1 から始まります。引数ゼロがあります。バイナリ自体の名前が常に保持されます。水が濁るのを避けるため、印刷は避けました。出力される引数は、コマンドラインで指定した引数だけです。
./glob one two 3 ant beetle cockroach
コマンドラインパラメータとして *.c を使用してそれを試してみましょう。
ls *.c
./glob *.c
現在のディレクトリに C ファイルが存在しない場合、シェルは *.c を find コマンドに渡します。次に、find コマンドはワイルドカード パターン自体に作用します。ただし、現在のディレクトリに C ファイルがある場合、シェルは一致する C ファイルの名前をプログラムに渡します。
ls *.c
./glob *.c
私たちのプログラムは C ファイルの名前をパラメータとして受け取ります。これは find コマンドにも当てはまります。つまり、実際には、find は指示どおりに実行していました。つまり、main.c ファイルを除くすべてのファイルを削除していました。
今回は、ワイルドカード パターンを一重引用符で囲みます。
ls *.c
./glob '*.c'
シェルは、グロビングをワイルドカード パターンに適用する機会を無視し、それをさらに処理するためにコマンドに直接渡します。
簡単な解決策、私を引用してください
原則として、find などのコマンドに渡すワイルドカード パターンは引用符で囲みます。この種の潜在的に悲惨な事故を防ぐために必要なのはこれだけです。