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

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

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

unzip "*".zip

しかし、その後にすべてのzipファイルを削除するには、

rm *.zip

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

なぜ違うのでしょうか? 私には、これはまったく同じ操作のように思えます。それとも、ワイルドカードを間違って使用しているのでしょうか?

ワイルドカードの紹介Unix ではこの点についてはあまり詳しく説明されておらず、またはドキュメントでも何も見つけられませんでしrmzip

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

答え1

状況を非常によく説明していただきました。パズルの最後のピースは、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$/:^]] ファイル[.zip] [ファイル(複数可) ...] [-x xファイル(複数可) ...] [-d exdir]

答え2

これら 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ユーティリティは、複数の圧縮ファイルを引数として呼び出すことはできません。しかし、開発者は別の方法を選択しました。man ページから引用:

ファイル[.zip]

[...] ワイルドカード表現は、一般的に使用されている Unix シェル (sh、ksh、csh) でサポートされているものと似ています [...] (オペレーティングシステムによって解釈または変更される可能性のある文字は必ず引用符で囲んでください。(特に Unix および VMS の場合)

答え3

違いは、最初のケースではシェル自体が glob を展開することです。

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

2 番目のケースでは、アプリケーション自体がその文字を使用して「何か」を実行します。

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

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

答え4

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 は glob 自体を解釈して異なる結果を生成することをサポートしています。

関連情報