Bagaimana cara "mengekstrak" file zip?

52

Saya mengekstrak file zip ke folder yang tidak kosong. File zip memiliki banyak file dan hierarki yang dalam, yang digabung dengan pohon yang ada dari direktori target. Bagaimana saya bisa menghapus file dan direktori yang dibuat dengan membuka ritsleting tanpa merusak file dan direktori yang sudah ada di sana? Tentu saja, saya masih memiliki file zip yang saya gabungkan, jadi informasinya ada di sana.

mafp
sumber
Umm terima kasih sudah menerima, tapi itu benar-benar ide @ jjin. Saya tidak mengetahui lqopsi untuk unzizp, saya hanya menambahkan beberapa trik * nix klasik di sekitar jawaban utamanya.
terdon
Tidak apa-apa, saya tidak terlalu peduli. Saya menambahkan versi saya sendiri tentang penanganan ruang putih yang berbeda.
jjlin
@terdon Ya ... Saya juga memilih jawaban jjlin, tetapi saya hanya bisa menerima satu jawaban.
mafp
Untuk referensi di masa mendatang, selalu lakukan salah satu dari yang berikut dengan arsip yang tidak dikenal dalam format apa pun: 1) Ekstrak ke direktori kosong atau 2) Daftarkan terlebih dahulu (unzip -l) sebelum mengekstraksi sehingga Anda dapat melihat apakah itu jahat seperti ini. Arsip yang dibuat tanpa direktori tingkat atas dengan segala sesuatu di bawah itu adalah bentuk yang buruk. Ketika selesai dengan tar, mereka sebenarnya disebut bom tar, jadi saya kira ini bisa disebut bom pos.
Joe
@ Jo Ini memiliki kegunaannya. Paket LaTeX, misalnya, dapat foo.tds.zipberupa formulir. Ritsleting ini bergabung menjadi pohon TEXMF, yang sangat nyaman. Tetapi jika Anda ingin menghapus paket seperti itu Anda dihadapkan dengan masalah yang saya jelaskan.
mafp

Jawaban:

27

Jawaban jjlin adalah caranya. Saya hanya ingin menambahkan beberapa pilihan untuk direktori:

  • Hapus semua file yang diekstraksi , tidak ada direktori :

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm "$n"; done
  • Hapus file yang diekstrak dan direktori kosong saja

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

    Tanpa opsi, rmdirhanya menghapus direktori kosong, itu akan meninggalkan file dan folder tidak kosong sendiri sehingga Anda dapat menjalankannya dengan aman *.

  • Hapus semua yang diekstraksi, tetapi minta konfirmasi sebelum setiap penghapusan:

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

    The -ibendera akan menyebabkan rmuntuk meminta sebelum setiap penghapusan, Anda dapat memilih Ya atau Tidak

  • Hapus semua yang diekstrak, termasuk direktori:

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm -rf "$n"; done
terdon
sumber
Menghapus direktori kosong mudah dilakukan dengan find: find * -depth -type d -exec rmdir {} +dan abaikan semua Directory not emptypesan. Mungkin legal untuk mempersingkat ini find * -type d -deletesebagai -deleteopsi aktif -depthtetapi saya belum memverifikasi bahwa -deletetidak akan menghapus direktori tidak kosong.
Adrian Pronk
@AdrianPronk tidak:find: cannot delete './foo': Directory not empty
terdon
28

Anda dapat menggunakan unzip -lqq <filename.zip>daftar isi file zip; ini akan mencakup beberapa info asing yang perlu Anda filter. Inilah perintah yang berfungsi untuk saya:

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

The awkekstrak perintah hanya nama-nama file dan direktori. Kemudian hasilnya diteruskan ke xargsuntuk menghapus semuanya. Saya menyarankan untuk melakukan run-run dari perintah (yaitu, dengan menghilangkan xargs rm -rfbagian) terlebih dahulu untuk memastikan hasilnya benar.

Perintah di atas akan memiliki masalah berurusan dengan jalur yang memiliki spasi putih. Versi (lebih rumit) ini harus memperbaikinya:

unzip -lqq file.zip | awk '{$1=$2=$3=""; sub(/ */, "", $0); printf "%s%s", $0, "\0"}' | xargs -0 rm -rf
jjlin
sumber
Ini sudah cukup dekat dengan apa yang ada dalam pikiran saya, tetapi unzip -lqqdaftar juga direktori yang ada di zip. Untuk saat ini, saya akan membiarkan semua direktori sendirian. Bagaimana menghapus semua direktori kosong di pohon mungkin menjadi pertanyaan lanjutan.
mafp
@ mafp Itu poin bagus tentang direktori. Anda dapat menambahkan grep -v '/$'ke dalam pipeline untuk melewati penghapusan direktori (yang semuanya memiliki garis miring, AFAICT).
jjlin
@terdon Sebenarnya saya pikir masalahnya dimulai pada awk, karena mencetak hanya $ 4 tidak akan mencetak path lengkap.
jjlin
Saya tidak berpikir Anda harus menggunakan -ropsi rm: yang sepertinya meminta masalah, terutama ketika dikombinasikan dengan -fopsi. Saya tidak akan menggunakan -fopsi sama sekali dalam skenario ini.
Adrian Pronk
1
@jjlin: grep -v '/$'hanya akan menghilangkan entri direktori dalam file ZIP. Mereka masih akan memasukkan entri yang merupakan file biasa dalam file ZIP tetapi merupakan direktori yang sudah ada sebelumnya di folder target. Karena alasan ini, akan lebih bijaksana untuk menghilangkannya-r
Adrian Pronk
11

Dengan sakelar -Z1, unzip akan mencantumkan tepat satu file per baris (dan bukan yang lain).

Dengan cara ini, Anda bisa menggunakannya

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

untuk menghapus semua file yang diekstrak dari file zip.

Perintah

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

akan menghapus direktori juga, tetapi Anda harus berhati-hati. Jika direktori sudah ada sebelum mengekstraksi file zip, semua file yang sudah ada di direktori tersebut akan dihapus juga.


Jika Anda akan mengekstrak kembali file zip, ada pendekatan lain yang dijamin untuk menangani nama file yang aneh.

Pertama-tama ekstrak file zip tempat Anda semula dimaksudkan untuk mengekstraknya:

unzip file.zip -d elsewhere

Sekarang, ubah ke direktori tempat Anda mengekstrak file secara tidak sengaja dan jalankan perintah berikut:

find elsewhere -type f -printf "%P\0" | xargs -0 -I {} rm '{}'
  • -type f hanya menemukan file (tidak ada direktori).

  • %P\0adalah path relatif (tanpa elsewhere/), diikuti oleh karakter nol.

  • -0membuat xargs memisahkan garis dengan karakter nol. Ini lebih dapat diandalkan, karena secara teori - nama file dapat berisi karakter baris baru.


Untuk menangani direktori sisa, Anda dapat menjalankan perintah:

find -type d -exec rmdir -p {} \; 2> /dev/null
  • -type d hanya menemukan direktori.

  • -exec rmdir -p {} \;dijalankan rmdir -p {}untuk setiap direktori yang telah ditemukan.

    {}adalah direktori yang telah ditemukan, dan -pswitch membuat rmdir juga menghapus direktori induknya yang kosong.

  • 2> /dev/null menekan pesan kesalahan yang akan muncul dari upaya untuk menghapus direktori yang tidak kosong atau yang sebelumnya dihapus.


Halaman manual terkait:

Dennis
sumber
+1 untuk membuat saya membaca zipinfohalaman manual.
terdon
Wah, itu membuatnya sedikit lebih mudah. :)
jjlin
2

Berikut ini adalah solusi (saya pikir) yang lebih mudah dan lebih aman

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

Apa yang dilakukan ini: Perintah unzip backquoted akan menghasilkan daftar apa yang ada di file asli Anda.

zip -m kemudian akan menggunakan daftar itu untuk menambahkan add masing-masing ke getmeoutofhere.zip dan menghapusnya dari direktori asli (jadi secara teoritis itu harus indent ke myoriginalfile.zip.

Kelemahannya adalah bahwa unzip -lqq akan menghasilkan beberapa teks tambahan, tanggal, waktu, filesize, dll. Ini akan menyebabkan zip -m menghasilkan pesan kesalahan tetapi ini seharusnya tidak mempengaruhi (kecuali Anda memiliki kasus yang tidak mungkin dari file dengan yang sama nama).

Harap dicatat bahwa ini tidak akan menghapus direktori yang dibuat selama unzip asli.

David E.
sumber
Pendekatan yang menarik, akan mengeksplorasi lebih lanjut.
mafp
1

Jika Anda mengekstrak file sedemikian rupa sehingga stempel waktu modifikasi dalam arsip tidak disimpan dalam salinan yang diekstrak (melainkan file yang diekstrak memiliki waktu modifikasi seperti biasanya) maka cara yang tepat untuk menyerang ini adalah melalui waktu modifikasi. Semua file yang diekstraksi memiliki stempel waktu modifikasi yang lebih baru daripada file yang ada yang paling baru dimodifikasi dalam direktori itu.

Ini situasi sederhana.

Misalkan tidak ada file yang ada di direktori saat ini disentuh selama setidaknya 24 jam. Karena itu, apa pun yang dimodifikasi dalam 24 jam terakhir adalah sampah dari zipfile.

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

Ini akan menemukan beberapa direktori juga, tetapi rmakan membiarkannya sendirian. Mereka dapat ditangani di babak kedua:

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

Setiap direktori yang baru-baru ini dimodifikasi dimodifikasi oleh zip. Jika rmdirberhasil menghapusnya, itu berarti mereka kosong. Direktori kosong yang disentuh oleh zip mungkin dibuat olehnya: yaitu berasal dari arsip. Kami tidak bisa 100% yakin. Mungkin saja pekerjaan unzip memasukkan beberapa file ke direktori yang ada yang kosong.

Jika findgranularity 24 jam tidak cukup baik untuk pekerjaan itu, karena file dalam pohon dimodifikasi terlalu baru, maka saya selanjutnya akan mempertimbangkan sesuatu yang sederhana: misalkan pekerjaan unzip tidak memasukkan apa pun ke subdirektori yang ada. Dengan kata lain, semua yang tidak di-zip adalah file di tingkat atas, atau subdirektori baru yang tidak ada sebelumnya, yang karenanya tidak berisi apa pun selain materi dari zip. Kemudian:

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

Sekarang kita buka filelistdi editor teks, dan tentukan entri pertama dalam daftar yang tidak berasal dari zip. Kami menghapus entri itu dan yang lainnya setelahnya. Yang tersisa adalah file dan direktori yang berasal dari zip. Pertama-tama kita secara visual memeriksa masalah-masalah seperti spasi dalam nama, dan kemunculan kutipan yang perlu diloloskan. Kami kemudian dapat menambahkan kutipan di sekitar segalanya, jika perlu: Berikut ini diasumsikan Anda menggunakan Vim:

:%s/.*/"&"/

Kemudian gabungkan semuanya menjadi garis besar:

:%j

Sekarang masukkan rm -rfdi depannya:

Irm - rf<ESC>

Jalankan baris di bawah kursor sebagai perintah shell:

!!sh<Enter>

Jelas, saya tidak akan mengotomatiskan langkah-langkah tugas ini, karena risiko menghapus file yang sudah ada di sana, atau mengacaukan karena masalah nama file.

Jika Anda akan pergi rute yang jelas untuk mendapatkan daftar jalur di zip, lalu tangkap ke file, lihat dengan sangat hati-hati dan mengubahnya menjadi penghapusan setelah melakukan pengeditan yang diperlukan.

Kaz
sumber