web-dev-qa-db-ja.com

ワイルドカード文字*がコマンドZipとrmで大きく異なるのはなぜですか?

いくつかのファイル操作を行うスクリプトを作成しました。ワイルドカード演算子*を使用して、あるタイプのすべてのファイルに関数を適用していますが、取得できないことが1つあります。このようなフォルダ内のすべてのファイルをunzipできます

unzip "*".Zip

ただし、後ですべてのZipファイルを削除するには、

rm *.Zip

つまり、引用符は必要ありません。一方、解凍すると、*を指定しただけでは機能しません(「ファイルが一致しなかった」という警告が表示されます)。

なぜこれが違うのですか?私には、これはまったく同じ操作のように見えます。または、ワイルドカードを誤って使用していますか?

ワイルドカードの概要 Unixの場合、これは実際には行われず、rmまたはZipドキュメントで何も見つけることができませんでした。

Mac(Yosemite)でターミナルを使用しています。

58
patrick

あなたは状況を非常によく説明しました。パズルの最後のピースは、unzipがワイルドカード自体を処理できることです。

http://www.info-Zip.org/mans/unzip.html

議論

ファイル[.Zip]

...

ワイルドカード式は、一般的に使用されているUnixシェル(sh、ksh、csh)でサポートされているものと類似しており、以下を含むことができます。

* 0個以上の文字のシーケンスに一致します

*ワイルドカードを引用することで、シェルがそれを展開するのを防ぎ、unzipがワイルドカードを認識し、独自のロジックに従って展開するようにします。

rmは、対照的に、それ自体ではワイルドカードをサポートしていません。したがって、ワイルドカードを引用しようとすると、rm代わりにファイル名でリテラルのアスタリスクを探します。

その理由unzip *.Zipが機能しないのは、unzipの構文では、複数のZipファイルを使用できないためです。複数のパラメータがある場合、2番目以降のパラメータはアーカイブ内のファイルであると想定します。

unzip [-Z] [-cflptTuvz [abjnoqsCDKLMUVWX $ /:^]] file [.Zip] [file(s)...] [-x xfile(s)...] [-d exdir]

69
Jeff Schaller

これら2つのコマンドの違いは、引用符付きの*文字です。シェルでコマンドを呼び出し、引数に*文字を使用すると、シェル自体が引数を評価します。この例を見てください:

$ ls
file1.Zip  file2.Zip  file3.Zip  file4.txt

*

$ ls *.Zip
file1.Zip  file2.Zip  file3.Zip

シェルはワイルドカードを評価し、次のようにコマンドを作成します。

$ ls file1.Zip  file2.Zip  file3.Zip

引用符付きのワイルドカードを使用すると、(文字通り)*.Zipという名前のファイルとして解釈されます。

$ ls "*".Zip
ls: cannot access *.Zip: No such file or directory

unzipユーティリティは、複数の圧縮ファイルを引数として呼び出すことはできません。しかし、開発者は別の方法を選択しました。マンページから:

ファイル[.Zip]

[...]ワイルドカード式は、一般的に使用されているUnixシェル(sh、ksh、csh)でサポートされているものと類似しています。[...](操作によって解釈または変更される可能性のある文字を必ず引用してくださいsystem、特にUnixとVMSで)

25
chaos

違いは、シェル自体がグロブを展開する最初のケースです。

% cd /                                                       
% echo *
Applications Library Network System Users Volumes bin cores ...
% 

一方、2番目のケースでは、アプリケーション自体がそのリテラル文字でSomething™を実行します。

% cd /
% Perl -E 'chdir "/tmp" or die; say for glob($ARGV[0])' "*"
com.Apple.launchd.aj4FEhYqm5
...

引用符で囲まれていない場合、シェルは最初にグロブを展開し、シェルグロブが展開されたものでコマンドが実行されます。

7
thrig

コマンドは、シェルによって処理された後に引数を受け取ります。

最初の処理では、引用符で囲まれていない*がシェルによって(パターンに一致する現在のディレクトリ(pwd)内のファイルのリストに)展開されます。

echo *.Zip

すべての.Zipファイルをリストします。しかし、echo "*".Zip"notになります。

最初の処理では、引用符で囲まれた"*"は展開されず、パラメーターとしてunzipコマンドに渡されます(引用符が削除された後)。コマンドunzipは、*.Zipのパラメーターを受け取ります。

$ echo unzip "*".Zip
unzip *.Zip

*をファイルのリストに展開するのは、unzipコマンドです。


この2つのコマンドがnotでまったく同じ最終アクションを実行し、誰が*の変更を展開するかについても興味深いです。

unzip "*".Zip                ### the command unzip expands `*.Zip`.
unzip *.Zip                  ### the Shell expands `*.Zip`.

最初のコマンドは*.Zipを受け取り、それを展開してすべてのファイルを処理します。 2番目のコマンドunzipは、pwd内のすべての.Zipファイルのリストを受け取りますが、unzip開発者が複数のZipファイルの展開を拒否することを選択したため、処理されません。

2
user79743

Zipが複数の引数を処理する方法のため、引用符が必要です。

rm:引数リストのすべてのファイルを削除します

Zip:最初の引数でファイルを解凍します。残りの引数のファイルのみを抽出します。

$ ls *.Zip
file1.Zip  file2.Zip  file3.Zip
$ unzip *.Zip
Archive:  file1.Zip
caution: filename not matched:  file2.Zip
caution: filename not matched:  file3.Zip

ご覧のとおり、file1.Zip内でfile2.Zipとfile3.Zipを見つけようとします

複数のZipファイルを一度に抽出できるようにするために、Zipはグロブ自体の解釈をサポートしていますが、結果は異なります。

0
eMBee