zipファイルを「抽出」する方法


52

空でないフォルダーにzipファイルを抽出しました。zipファイルには多くのファイルと深い階層があり、それらはターゲットディレクトリの既存のツリーとマージされます。既に存在するファイルとディレクトリを破壊せずに、解凍によって作成されたファイルとディレクトリを削除するにはどうすればよいですか?もちろん、私はまだマージしたzipファイルを持っているので、情報はそこにあります。


受け入れてくれてありがとう。でも@jjinのアイデアでした。のlqオプションについては知りませんでしたが、unzizp彼の主な答えに古典的な* nixのトリックをいくつか追加しました。
テルドン

大丈夫、私はあまり気にしません。とにかく、独自の異なるバージョンの空白処理を追加しました。
jjlin

@terdonええ...私もjjlinの答えを支持しましたが、1つの答えしか受け入れられません。
mafp

将来の参考のために、次のいずれかの形式の見慣れないアーカイブで常に1つを実行します。最上位ディレクトリなしで作成されたアーカイブは、その下にあるすべてのものが悪い形式です。タールで処理されると、それらは実際にはタール爆弾と呼ばれます。
ジョー

@Joeそれには用途があります。LaTeXパッケージは、たとえば、foo.tds.zipフォームで提供されます。これらのzipはTEXMFツリーにマージされ、非常に便利です。しかし、そのようなパッケージを削除したい場合は、私が説明した問題に直面しています。
mafp

回答:


28

jjlinの答えは、進むべき道です。ディレクトリにいくつかの選択肢を追加したいだけです。

  • 抽出されたファイルをすべて削除し、ディレクトリは削除しません

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm "$n"; done
    
  • 抽出されたファイルと空のディレクトリのみを削除します

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm "$n"; done; rmdir *
    

    オプションなしで、rmdir空のディレクトリのみを削除します。ファイルと空でないフォルダはそのままにして、安全に実行できます*

  • 抽出したすべてを削除しますが、削除する前に確認を求めます:

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm -ri "$n"; done; rmdir *
    

    -iフラグが発生しますrm[はい]または[いいえ]を選択することができ、すべての除去の前にプロンプトに

  • 抽出されたすべてを削除します。ディレクトリが含まれます:

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm -rf "$n"; done
    

空のディレクトリの削除はfind:で簡単に行え、find * -depth -type d -exec rmdir {} +すべてのDirectory not emptyメッセージを無視します。これを短縮するために、法的かもしれないfind * -type d -deleteとして-deleteオプションがオン-depthが、私はそれを検証していない-delete非空のディレクトリを削除しません。
エイドリアンプロンク

@AdrianPronkそれはありません:find: cannot delete './foo': Directory not empty
terdon

28

を使用unzip -lqq <filename.zip>して、zipファイルの内容をリストできます。ただし、これには、除外する必要がある外部情報が含まれます。私に役立つコマンドを次に示します。

unzip -lqq file.zip | awk '{print $4;}' | xargs rm -rf

このawkコマンドは、ファイルとディレクトリの名前のみを抽出します。次に、結果が渡されxargsてすべてが削除されます。xargs rm -rf結果が正しいことを確認するために、最初にコマンドの予行演習を行うことをお勧めします(つまり、一部を省略して)。

上記のコマンドには、空白を含むパスの処理に問題があります。この(より複雑な)バージョンはそれを修正するはずです:

unzip -lqq file.zip | awk '{$1=$2=$3=""; sub(/ */, "", $0); printf "%s%s", $0, "\0"}' | xargs -0 rm -rf

これはすでに私が念頭に置いていたものに非常に近いものですがunzip -lqq、zipに含まれるディレクトリもリストしています。今のところ、私はすべてのディレクトリを単独で許可します。ツリー内のすべての空のディレクトリを削除する方法は、追加の質問かもしれません。
mafp

@mafpそれはディレクトリについての良い点です。grep -v '/$'パイプラインに追加して、ディレクトリ(すべての末尾にスラッシュがあるAFAICT)の削除をスキップできます。
jjlin

@terdon実際には、awk$ 4だけを印刷しても完全なパスが印刷されないため、問題はから始まると思います。
jjlin

-rrm のオプションを使用する必要はないと思います。これは、特に-fオプションと組み合わせた場合に問題を引き起こしているようです。-fこのシナリオでは、このオプションをまったく使用しません。
エイドリアンプロンク

1
@jjlin:grep -v '/$'ZIPファイルのディレクトリエントリのみを省略します。これらには、ZIPファイル内のプレーンファイルであるが、ターゲットフォルダー内の既存のディレクトリであるエントリが引き続き含まれます。このため、省略するのが賢明です-r
エイドリアンプロンク

11

スイッチを使用すると-Z1、unzipは1行につき1つのファイルのみをリストします(それ以外は何もリストしません)。

この方法では、使用できます

unzip -Z1 | xargs -I {} rm '{}'

zipファイルから抽出されたすべてのファイルを削除します。

コマンド

unzip -Z1 | xargs -I {} rm -rf '{}'

ディレクトリも削除されますが、注意する必要があります。zipファイルを抽出する前にディレクトリがすでに存在していた場合、それらのディレクトリ内の既存のファイルもすべて削除されます。


とにかくzipファイルを再抽出する場合、奇妙なファイル名を処理することが保証されている別のアプローチがあります。

最初にzipファイルを元の場所に解凍します:

unzip file.zip -d elsewhere

次に、誤ってファイルを抽出したディレクトリに移動し、次のコマンドを実行します。

find elsewhere -type f -printf "%P\0" | xargs -0 -I {} rm '{}'
  • -type f ファイルのみを検索します(ディレクトリは検索しません)。

  • %P\0相対パス(なしelsewhere/)で、その後にヌル文字が続きます。

  • -0xargsをヌル文字で行を区切ります。理論的には、ファイル名に改行文字を含めることができるため、これはより信頼性が高くなります。


残りのディレクトリを処理するには、次のコマンドを実行できます。

find -type d -exec rmdir -p {} \; 2> /dev/null
  • -type d ディレクトリのみを検索します。

  • -exec rmdir -p {} \;rmdir -p {}見つかったすべてのディレクトリに対して実行されます。

    {}は見つかったディレクトリで、-pスイッチはrmdirに空の親ディレクトリも削除させます。

  • 2> /dev/null 空でないディレクトリまたは以前に削除されたディレクトリを削除しようとすると発生するエラーメッセージを抑制します。


関連マニュアルページ:


zipinfoのmanページを読んでくれた+1 。
テルドン

まあ、それは少し簡単になります。:)
jjlin

2

さらに簡単で安全な(私は思う)ソリューションがあります

zip -m getmeoutofhere.zip `unzip -lqq myoriginalzipfile.zip`
rm getmeoutofhere.zip

これがしていること:逆引用符で囲まれたunzipコマンドは、元のファイルにあったもののリストを生成します。

zip -mはそのリストを使用して、それぞれをgetmeoutofhere.zipに追加し、元のディレクトリから削除します(したがって、理論的にはmyoriginalfile.zipに必要です)。

欠点は、unzip -lqqが余分なテキスト、日付、時刻、ファイルサイズなどを生成することです。これらにより、zip -mがエラーメッセージを生成しますが、影響はありません(同じファイルを持つ可能性が低い場合を除きます)名前)。

元の解凍中に作成されたディレクトリは削除されないことに注意してください。


興味深いアプローチは、さらに探求します。
mafp

1

アーカイブ内の変更タイムスタンプが抽出されたコピーに保存されないようにファイルを抽出した場合(しかし、抽出されたファイルには通常の変更時間があります)、これを攻撃する正しい方法は変更時間です。抽出されたすべてのファイルには、そのディレクトリ内で最後に変更された既存のファイルよりも新しい変更タイムスタンプがあります。

これは簡単な状況です。

少なくとも24時間、現在のディレクトリにある既存のファイルがどれも操作されていないとします。したがって、過去24時間以内に変更されたものはすべて、zipファイルからジャンクされます。

$ find . -mtime -1 -print0 | xargs -0 rm

これはいくつかのディレクトリも見つけますが、rmそれらはそのままにしておきます。これらは2番目のパスで対処できます。

$ find . -mtime 1 -type d -print 0 | xargs -0 rmdir

最近変更されたディレクトリはすべて、zipによって変更されました。rmdirそれらが正常に削除された場合、それは空であることを意味します。zipで変更された空のディレクトリは、おそらくそれによって作成されました。つまり、アーカイブから取得されたものです。100%確信することはできません。解凍ジョブが空の既存のディレクトリにいくつかのファイルを置く可能性があります。

findツリーのファイルがあまりにも最近変更されたため、ジョブの24時間の細分性が十分ではない場合、次に簡単なことを検討します。unzipジョブが既存のサブディレクトリに何も入れなかったとします。つまり、解凍されたものはすべて、最上位のファイルか、以前は存在しなかった新しいサブディレクトリのいずれかであり、したがって、zipからの素材のみが含まれています。次に:

# list directory in descending order of modification time
$ ls -1t > filelist  # descending order of modification time

ここfilelistで、テキストエディタで開き、zipから来ていないリストの最初のエントリを決定します。そのエントリとその後のすべてを削除します。残っているのは、zipから取得したファイルとディレクトリです。最初に、名前のスペースやエスケープする必要がある引用符の出現などの問題を視覚的に検査します。その後、必要に応じて、すべてを引用符で囲むことができます。以下では、Vimを使用することを想定しています。

:%s/.*/"&"/

次に、すべてを1つの大きな行に結合します。

:%j

次にrm -rf、その前に挿入します。

Irm - rf<ESC>

シェルコマンドとしてカーソルの下の行を実行します。

!!sh<Enter>

確かに、すでに存在していたファイルを消去したり、ファイル名の問題のために台無しにしたりするリスクがあるため、このタスクのステップを自動化しません。

zip内のパスのリストを取得する明白なルートをたどり、それをファイルにキャプチャし、非常に慎重に調べて、必要な編集を行った後に削除に変換します。

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