いくつかのファイル操作を行うスクリプトを作成しました。ワイルドカード演算子*
を使用して、あるタイプのすべてのファイルに関数を適用していますが、取得できないことが1つあります。このようなフォルダ内のすべてのファイルをunzip
できます
unzip "*".Zip
ただし、後ですべてのZipファイルを削除するには、
rm *.Zip
つまり、引用符は必要ありません。一方、解凍すると、*を指定しただけでは機能しません(「ファイルが一致しなかった」という警告が表示されます)。
なぜこれが違うのですか?私には、これはまったく同じ操作のように見えます。または、ワイルドカードを誤って使用していますか?
ワイルドカードの概要 Unixの場合、これは実際には行われず、rm
またはZip
ドキュメントで何も見つけることができませんでした。
Mac(Yosemite)でターミナルを使用しています。
あなたは状況を非常によく説明しました。パズルの最後のピースは、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]
これら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で)
違いは、シェル自体がグロブを展開する最初のケースです。
% 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
...
引用符で囲まれていない場合、シェルは最初にグロブを展開し、シェルグロブが展開されたものでコマンドが実行されます。
コマンドは、シェルによって処理された後に引数を受け取ります。
最初の処理では、引用符で囲まれていない*
がシェルによって(パターンに一致する現在のディレクトリ(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
ファイルの展開を拒否することを選択したため、処理されません。
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はグロブ自体の解釈をサポートしていますが、結果は異なります。