Come "sottrarre" un file zip?


52

Ho estratto un file zip in una cartella non vuota. Il file zip ha molti file e una gerarchia profonda, che si sono fusi con l'albero esistente della directory di destinazione. Come posso rimuovere i file e le directory che sono stati creati decomprimendo senza distruggere i file e le directory che erano già lì? Certo, ho ancora il file zip che ho unito, quindi le informazioni sono lì.


Grazie Umm per l'accettazione, ma è stata davvero l'idea di @Jjin. Non ero a conoscenza delle lqopzioni per unzizp, ho appena aggiunto alcuni trucchi classici * nix intorno alla sua risposta principale.
terdon,

Va bene, non mi interessa molto. Ho comunque aggiunto la mia versione diversa della gestione degli spazi bianchi.
jjlin,

@terdon Sì ... Anche io ho votato a favore della risposta di Jjlin, ma posso accettare solo una risposta.
mafp,

Per riferimento futuro, eseguire sempre una delle seguenti operazioni con un archivio sconosciuto di qualsiasi formato: 1) Estrarlo in una directory vuota o 2) Elencarlo prima (decomprimere -l) prima di estrarlo in modo da poter vedere se è brutto in questo modo. Archivi realizzati senza una directory di livello superiore con tutto ciò che è in cattive condizioni. Quando hanno finito con il catrame, in realtà sono chiamate bombe di catrame, quindi immagino che questo potrebbe essere chiamato una bomba con zip.
Joe,

@Joe Ha i suoi usi. I pacchetti LaTeX, ad esempio, possono presentarsi in una foo.tds.zipforma. Queste cerniere si fondono in un albero TEXMF, il che è molto conveniente. Ma se mai vuoi rimuovere un tale pacchetto devi affrontare il problema che ho descritto.
mafp,

Risposte:


28

La risposta di Jjlin è la strada da percorrere. Voglio solo aggiungere alcune scelte per le directory:

  • Elimina tutti i file estratti , nessuna directory :

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm "$n"; done
    
  • Elimina solo i file estratti e svuota le directory

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

    Senza opzioni, rmdirelimina solo le directory vuote, lascerà da soli i file e le cartelle non vuote in modo da poterlo eseguire in sicurezza *.

  • Elimina tutto ciò che è stato estratto, ma richiedi una conferma prima di ogni eliminazione:

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

    Il -iflag farà rmapparire prima di ogni rimozione, puoi scegliere Sì o No.

  • Elimina tutto ciò che è stato estratto, directory incluse:

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

L'eliminazione di directory vuote viene eseguita facilmente con find: find * -depth -type d -exec rmdir {} +e ignora tutti i Directory not emptymessaggi. Potrebbe essere legale accorciarlo a find * -type d -deletequando l' -deleteopzione si attiva -depthma non ho verificato che -deletenon eliminerà una directory non vuota.
Adrian Pronk,

@AdrianPronk no:find: cannot delete './foo': Directory not empty
terdon

28

È possibile utilizzare unzip -lqq <filename.zip>per elencare i contenuti del file zip; questo includerà alcune informazioni estranee che dovrai filtrare, comunque. Ecco un comando che funziona per me:

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

Il awkcomando estrae solo i nomi dei file e delle directory. Quindi il risultato viene passato xargsper eliminare tutto. Suggerisco di eseguire un ciclo a secco del comando (ovvero omettendo la xargs rm -rfparte) per assicurarsi che i risultati siano corretti.

Il comando sopra avrà problemi con i percorsi che hanno spazi bianchi. Questa versione (più complicata) dovrebbe risolvere questo:

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

Questo è già abbastanza vicino a quello che avevo in mente, ma unzip -lqqelenca anche le directory contenute nello zip. Per ora, avrei lasciato tutte le directory da solo. Come eliminare tutte le directory vuote in un albero potrebbe essere una domanda di follow-up.
mafp,

@mafp Questo è un aspetto positivo delle directory. È possibile aggiungere grep -v '/$'nella pipeline per saltare l'eliminazione delle directory (che hanno tutte una barra finale, AFAICT).
jjlin,

@terdon In realtà penso che il problema abbia inizio awkdal momento che la stampa di soli $ 4 non stampa l'intero percorso.
jjlin,

Non penso che dovresti usare l' -ropzione di rm: sembra che tu stia chiedendo problemi, specialmente se combinato con l' -fopzione. Non userei affatto l' -fopzione in questo scenario.
Adrian Pronk,

1
@jjlin: ometterà grep -v '/$'solo le voci della directory nel file ZIP. Includeranno comunque voci che erano semplici file nel file ZIP ma erano directory preesistenti nella cartella di destinazione. Per questo motivo, sarebbe saggio omettere-r
Adrian Pronk,

11

Con l'opzione -Z1, decomprimere elencherà esattamente un file per riga (e nient'altro).

In questo modo, puoi usare

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

per eliminare tutti i file estratti dal file zip.

Il comando

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

eliminerà anche le directory, ma devi stare attento. Se le directory esistevano già prima di estrarre il file zip, verranno eliminati anche tutti i file preesistenti in quelle directory.


Se hai intenzione di riestrarre il file zip comunque, c'è un altro approccio che è garantito per gestire strani nomi di file.

Per prima cosa estrai il file zip dove inizialmente intendevi estrarlo:

unzip file.zip -d elsewhere

Ora, cambia nella directory in cui hai estratto i file per errore ed esegui il seguente comando:

find elsewhere -type f -printf "%P\0" | xargs -0 -I {} rm '{}'
  • -type f trova solo i file (nessuna directory).

  • %P\0è il percorso relativo (senza elsewhere/), seguito da un carattere null.

  • -0rende xargs linee separate da caratteri null. Ciò è più affidabile, poiché - in teoria - i nomi dei file possono contenere caratteri di nuova riga.


Per gestire le directory rimanenti, è possibile eseguire il comando:

find -type d -exec rmdir -p {} \; 2> /dev/null
  • -type d trova solo le directory.

  • -exec rmdir -p {} \;viene eseguito rmdir -p {}per ogni directory che è stata trovata.

    {}è la directory che è stata trovata e l' -popzione fa sì che rmdir rimuova anche le sue directory padre vuote.

  • 2> /dev/null elimina i messaggi di errore derivanti dal tentativo di eliminare directory non vuote o precedentemente eliminate.


Pagine man correlate:


+1 per avermi fatto leggere zipinfola pagina man.
terdon,

Bene, accidenti, questo rende un po 'più facile. :)
jjlin,

2

Ecco una soluzione ancora più semplice e sicura (credo)

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

Cosa sta facendo: il comando unzip retroquotato produrrà un elenco di ciò che era nel file originale.

zip -m userà quindi quell'elenco per aggiungere aggiungere quello per getmeoutofhere.zip e rimuoverlo dalla directory originale (quindi teoricamente dovrebbe essere indifferente a myoriginalfile.zip.

Il rovescio della medaglia è che decomprimere -lqq produrrà del testo extra, date, orari, dimensione del file, ecc. Ciò causerà zip -m per produrre messaggi di errore, ma ciò non dovrebbe avere alcun effetto (a meno che tu non abbia il caso improbabile di un file con lo stesso nome).

Si noti che ciò non rimuoverà alcuna directory creata durante la decompressione originale.


Approccio interessante, esplorerà ulteriormente.
mafp,

1

Se hai estratto i file in modo tale che il timestamp di modifica nell'archivio non sia conservato nelle copie estratte (ma piuttosto i file estratti hanno il loro solito tempo di modifica), il modo giusto per attaccare è attraverso il tempo di modifica. Tutti i file estratti hanno un timestamp di modifica più recente rispetto al file esistente modificato più di recente in quella directory.

Ecco una situazione semplice.

Supponiamo che nessuno dei file esistenti nella directory corrente sia stato toccato per almeno 24 ore. Tutto ciò che è stato modificato nelle ultime 24 ore è quindi spazzatura dal file zip.

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

Questo troverà anche alcune directory, ma rmle lascerà in pace. Possono essere trattati in un secondo passaggio:

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

Tutte le directory che sono state recentemente modificate sono state modificate dallo zip. Se rmdirli rimuove correttamente, significa che sono vuoti. Le directory vuote che sono state toccate da zip sono state probabilmente create da esso: cioè provenivano dall'archivio. Non possiamo esserne sicuri al 100%. È possibile che il processo di decompressione inserisca alcuni file in una directory esistente che era vuota.

Se findla granularità di 24 ore non è abbastanza buona per il lavoro, perché i file nella struttura sono stati modificati troppo di recente, allora prenderei in considerazione qualcosa di semplice: supponiamo che il lavoro di decompressione non abbia inserito nulla nelle sottodirectory esistenti. Vale a dire, tutto ciò che è stato decompresso è o un file al livello più alto, o una nuova sottodirectory che prima non c'era, che quindi non contiene altro che materiale dalla zip. Poi:

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

Ora apriamo filelistin un editor di testo e determiniamo la prima voce nell'elenco che non proviene dalla zip. Cancelliamo quella voce e tutto il resto dopo di essa. Ciò che rimane sono i file e le directory che provengono dalla zip. Innanzitutto ispezioniamo visivamente eventuali problemi come spazi nei nomi e occorrenze di citazioni che devono essere evitate. Possiamo quindi aggiungere virgolette intorno a tutto, se necessario: Quanto segue presuppone che tu usi Vim:

:%s/.*/"&"/

Quindi unisci tutto in una grande linea:

:%j

Ora inseriscilo rm -rfdi fronte:

Irm - rf<ESC>

Esegui la linea sotto il cursore come comando shell:

!!sh<Enter>

Sicuramente, non automatizzerei i passaggi di questa attività, a causa del rischio di cancellare i file che erano già lì o rovinare a causa di problemi con i nomi dei file.

Se stai andando sulla strada ovvia per ottenere un elenco dei percorsi nella zip, quindi acquisiscilo in un file, guardalo attentamente e trasformalo in una rimozione dopo aver effettuato tutte le modifiche necessarie.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.