ワイルドカード文字*がコマンドzipとrmでそれほど異なるのはなぜですか?


58

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

unzip "*".zip

ただし、すべてのzipファイルを後で削除するには、する必要があります

rm *.zip

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

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

Unixでのワイルドカードの紹介は実際にはこれに該当せずrmzipドキュメントやドキュメントには何も見つかりませんでした。

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


4
unzip通常のfor f in *.zip;do...doneシェルループなしでこれを実行できるとは思いもしませんでした。このような奇妙な非UNIXライクなコマンドラインUI。
ピーターコーデス

@ピーター状況を誤解していると思います。unzipグロブをアーカイブのコンテンツに適用します。ワイルドカードを使用してbashから取得することはできません。(あなたがFのために`` `必要があると思いますunzip -l archive.zip。やる... done`)
アレクシス

@alexis:unzip単一のzipファイル内で一致するグロブを受け入れることを知っていました。しかし、これは異なります。unzip '*.zip'複数のzipファイルがあるディレクトリで実際に試したところ、すべてのzipからすべてのファイルが抽出されました。私が言ったように、非常に奇妙です。 tarそのような操作モードはありません。
ピーターコーデス

1
@Peterなるほど...ええ、それは奇妙です、特にunzip は複数のコマンドライン引数を受け入れないからです!明らかにWindowsのみの実装です。OPのタスクの説明を誤って解釈しました。
アレクシス

1
@alexis:PKZipはWindowsより前の日付です。これはDOSコマンドラインプログラムで、1989年に最初にリリースされました。Unixポートは基本的に同じコマンドライン解析コードAFAIKを使用します。
ピーターコーデス

回答:


68

あなたは状況を非常によく説明しました。パズルの最後の部分は、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]


6
ありがとう、それは理にかなっています!私が正しく理解していれば、ある場合には私unzip自身の言語を話し、別の場合には一般的なUnixの専門用語を話しますか?
パトリック

6
正しい。シェルが行うこととプログラムが行うことを念頭に置くことが重要です。
ジェフシャラー

7
pkzipは、プログラムに渡されるワイルドカードを展開しなかったDOSで作成されました。
トールビョーンラヴンアンデルセン

11
@patrick一度に1つのファイルしか処理できないプログラムで複数のファイルを処理するUnixの方法は、ループを使用することです。例えばfor f in *.zip ; do unzip -v "$f" ; done。そして、シェルがファイル名の展開などを行う理由の大部分は、個々のプログラムが必要ないことです(これは、小さいながらも迷惑な方法で異なった多くのワイルドカード展開の独立して記述された実装を持つことになります) 。
cas

25

これら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ファイルを呼び出すことはできません。しかし、開発者は別の方法を選択しました。マンページから:

ファイル[.zip]

[...]ワイルドカード式は、一般的に使用されるUnixシェル(sh、ksh、csh)でサポートされているものに似ています[...](オペレーティングシステム、特にUnixおよびVMS。)


unzip複数のzipファイルを引数として許可するのではなく、著者がそのルートを選択した理由を知っていますか?
デビッドエトラー

@DavidEtler私も知りません。
カオス

1
@DavidEtlerでも、理由は言えませんが、as-builtのunzipの構文は、zipファイルの内容であると想定されるzipファイルの後のファイル名を受け入れます。2つ目のzipファイルを「unzip me」パラメーターにするか、「この内部zipファイルを前のアーカイブからアンパックする」パラメーターにするかはあいまいです。
ジェフシャラー

@DavidEtlerは、開発者が何を考えていたのかわかりませんが、当時はすべてがはるかに遅く、小さかったです。通常、一度に複数のzipファイルを処理することはありませんでした。90キロバイトまたは250キロバイトを保持するフロッピーがあり、10 MBのディスクドライブを用意して本当に満足していました。システム間トランスポートのためだけではなく、物事が圧縮されたためです。
ジョー

7

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

% 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
...

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


2

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

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

echo *.zip

すべての.zipファイルをリストします。しかしecho "*".zip"意志ではありません

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

$ echo unzip "*".zip
unzip *.zip

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


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

unzip "*".zip                ### the command unzip expands `*.zip`.
unzip *.zip                  ### the shell expands `*.zip`.

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


0

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はそれ自体でグロブの解釈をサポートしますが、結果は異なります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.