Come de-decomprimere, de-tar -xvf - de-unarchive in una cartella disordinata?


14

Di solito, io disarchivo le cose $ mkdir newFolder; $ mv *.zip newFolder; $ cd newFolder; $unzip *.zipma a volte divento pigro e faccio semplicemente in una cartella arbitraria, $ unzip *.zipcosì di tanto in tanto confondendo altri contenuti. Elencherò qui alcuni metodi: alcune versioni di archivio hanno sicuramente delle merde, mentre altre sono più spartane, sono più interessato a queste ultime.

Alcuni modi per disarchiviare, ce ne sono altri?

  1. $ find . -anewer fileThatExistedBeforeUnarchieving -ok rm '{}' \;I punti deboli sono che elenca le *.zipdirectory, quindi è necessario utilizzare slow -ok, slow con molte *.zipcorrispondenze e, per qualche motivo, non sembra corrispondere a tutto quello estratto.

  2. Se una piccola quantità di file estratti, uno per uno, lento, ingombrante e soggetto a errori.

  3. Quando voglio assicurarmi che il contenuto dell'archieve sia effettivamente una cartella, a volte lo controllo con $ unzip -l *.bsd, funziona almeno nella versione unzip di obsd.

Se ti riferisci a determinati strumenti di archiviazione, per favore, indicali quando appropriato. Mantienilo semplice però - Sono più interessato ai modi in cui lo fai, piuttosto che a un singolo strumento.



Ecco uno script che uso per automatizzare le mkdir; unzipcose, quindi non sono mai troppo pigro per farlo! svn.mikelward.com/svn/scripts/untar
Mikel

2
Vedi questa domanda e risposte correlate: unix.stackexchange.com/questions/5123/…
alex

Risposte:


11

Per nome

Puoi generare l'elenco di file nell'archivio ed eliminarli, anche se questo è fastidiosamente complicato con gli archivi come decomprimere o 7z che non hanno un'opzione per generare un semplice elenco di nomi di file. Anche con tar, questo presuppone che non ci siano nuove righe nei nomi dei file.

tar tf foo.tar | while read -r file; do rm -- "$file" done
unzip -l foo.zip | awk '
    p && /^ --/ {p=2}
    p==1 {print substr($0, 29)}
    /^ --/ {++p}
' | while …
unzip -l foo.zip | tail -n +4 | head -n -2 | while …  # GNU coreutils only
7z l -slt foo.zip | sed -n 's/^Path = //p' | while …  # works on tar.*, zip, 7z and more

Invece di rimuovere i file, è possibile spostarli nella destinazione prevista.

tar tf foo.tar | while read -r file; do
  if [ -d "$file" ]; then continue; fi
  mkdir -p "/intended/destination/${file%/*}"
  mv -- "$file" "/intended/destination/$file"
done

Utilizzando FUSE

Invece di dipendere da strumenti esterni, è possibile (nella maggior parte dei computer) utilizzare FUSE per manipolare gli archivi utilizzando i normali comandi del filesystem.

Puoi usare Fuse-zip per sbirciare in una zip, estrarla con cp, elencarne il contenuto con find, ecc.

mkdir /tmp/foo.d
fuse-zip foo.zip /tmp/foo.d
## Remove the files that were extracted mistakenly (GNU/BSD find)
(cd /tmp/foo.d && find . \! -type d -print0) | xargs -0 rm
## Remove the files that were extracted mistakenly (zsh)
rm /tmp/foo.d/**(:"s~/tmp/foo.d/~~"^/)
## Extract the contents where you really want them
cp -Rp /tmp/foo.d /intended/destination
fusermount -u foo.d
rmdir foo.d

AVFS crea una vista dell'intera gerarchia di directory in cui tutti gli archivi hanno una directory associata (lo stesso nome con # virata alla fine) che sembra contenere il contenuto dell'archivio.

mountavfs
## Remove the files that were extracted mistakenly (GNU/BSD find)
(cd ~/.avfs/"$PWD/foo.zip#" && find . \! -type d -print0) | xargs -0 rm
## Remove the files that were extracted mistakenly (zsh)
rm ~/.avfs/$PWD/foo.zip\#/**/*(:"s~$HOME/.avfs/$PWD/foo.zip#~~"^/)
## Extract the contents where you really want them
cp -Rp ~/.avfs/"$PWD/foo.zip#" /intended/destination
umountavfs

Per data

Supponendo che non vi sia stata alcuna altra attività nella stessa gerarchia della tua estrazione, puoi dire i file estratti dal loro recente ctime . Se hai appena creato o spostato il file zip, puoi usarlo come cutoff; altrimenti utilizzare ls -lctrper determinare un tempo di interruzione adeguato. Se vuoi assicurarti di non rimuovere le cerniere, non c'è motivo di approvare manualmente: findè perfettamente in grado di escluderle. Ecco alcuni comandi di esempio che usano zsh o find; notare che le primarie -cmine -cnewernon sono in POSIX ma esistono su Linux (e altri sistemi con GNU find), * BSD e OSX.

find . \! -name '*.zip' -type f -cmin -5 -exec rm {} +  # extracted <5 min ago
rm **/*~*.zip(.cm-6)  # zsh, extracted ≤5 min ago
find . -type f -cnewer foo.zip -exec rm {} +  # created or moved after foo.zip

Con GNU find, FreeBSD e OSX, un altro modo per specificare il tempo di cutoff è quello di creare un file e usare touchper impostare il suo mtime al tempo di cutoff.

touch -d … cutoff
find . -type f -newercm cutoff -delete

Invece di rimuovere i file, è possibile spostarli nella destinazione prevista. Ecco un modo con GNU / * BSD / OSX find, creando directory nella destinazione secondo necessità.

find . \! -name . -cmin -5 -type f -exec sh -c '
    for x; do
      mkdir -p "$0/${x%/*}"
      mv "$x" "$0/$x"
    done
  ' /intended/destination {} +

Zsh equivalente (quasi: questo riproduce l'intera gerarchia di directory, non solo le directory che conterranno i file):

autoload zmv
mkdir -p ./**/*(/cm-3:s"|.|/intended/destination|")
zmv -Q '(**/)(*)(.cm-3)' /intended/destination/'$1$2'

Attenzione, non ho testato la maggior parte dei comandi in questa risposta. Rivedi sempre l'elenco dei file prima di rimuoverlo (esegui echoprima, quindi rmse è ok).


Finalmente ho riscontrato questo problema oggi. Come radice! Alla fine ho usato una combinazione di "Per nome" e "Per data"
phunehehe

1

Mi sento stupido, comunque mi sono grattato la testa per scrivere questa sceneggiatura quando ho avuto un problema simile. Ho usato cpiocon la -itbandiera per ottenere un elenco di file; puoi usare comandi equivalenti per altri archivi. La parte difficile è che l'archivio cpio proviene da un initrd e l'ho estratto /, quindi molte cartelle e file hanno lo stesso nome di un sistema funzionante. Fortunatamente cpio non ha sovrascritto nessuno dei miei file esistenti. Uso un controllo del tempo per assicurarmi di non cancellare nulla che esistesse prima del comando sbagliato.

#! /bin/sh

files=$(cpio -it < /mnt/temp/lglive.cpio)

for i in ${files}
do
    name=$(stat -c "%n" ${i})
    time=$(stat -c "%Y" ${i})
    # Time of the creation of the mess: 1296457595
    if [[ ${time} -gt 1296457590 && ${time} -lt 1296457600 ]]
    then
        if [[ -f ${name} ]]
        # If it is a file, it must have been created as part of the mess.
        then
            echo "rm ${name}"
        elif [[ -d ${name} ]]
        # If it is a directory, it may have been part of the mess
        # or maybe some files underneath it is created as part of the mess.
        then
            if [[ $(ls -A ${name}) ]]
            # If the directory contains something then don't delete it.
            then
                echo "${name} is not empty"
            # If the directory is empty then assume it is rubbish.
            else
                echo "rmdir ${name}"
            fi
        fi
    fi
done

echo "Files and directories still exist after the removal:"
for i in ${files}
do
    if [[ -e ${i} ]]
    then
        echo ${i}
    fi
done

0

Che ne dici di alimentare l'elenco dei file in archivio xargs rm?

Sarebbe tar -tf tarbomb.tar | xargs rmo unzip --list zipbomb.zip | xargs rm.


2
I comandi forniti non funzioneranno nel caso generale, e questo è pericoloso poiché stai rimuovendo i file. xargssi aspetta che il suo input sia citato in un modo peculiare che findnon produce. Utilizzare in xargs -I rm {}modo che xargs elabori invece un elemento per riga. Per il comando unzip, quale implementazione hai? Il mio (Debian / Ubuntu) non ha --list, solo -l, e non stampa solo i nomi dei file, quindi è necessaria un'ulteriore elaborazione.
Gilles 'SO- smetti di essere malvagio' il

@Gilles: 1) sì, è pericoloso, ma dato che presumibilmente abbiamo sovrascritto i file originali, sono già spariti. 2) Non stavo parlando find. 3) hai ragione unzip, non ho testato e sembra che non ci sia alcuna opzione per la lista non decorata. No anche --listsu Ubuntu - non ho provato.
alex

Mi dispiace per la risposta predefinita, sostituire tar -tper find. Ma i miei altri punti sono validi. Esiste il rischio reale che il comando come indicato eliminerebbe un file non correlato.
Gilles 'SO- smetti di essere malvagio' il

tar -tf tarbomb.tarstamperà i nomi dei file uno per riga, quindi potresti farlo tar -tf tarbomb.tar | while IFS=$'\n' read -r filename; do rm "$filename"; doneo simili.
Mikel,

0

Non proprio quello che hai chiesto, ma che ne dici di usare uno script "decomprimere tutto" invece di.

unzip *.zip

In questo modo l'output di ciascun file va nella sua directory.

#!/bin/bash
for f in *.zip ; do unzip -n "$f" -d "${f/%zip/out}"; done

0

Uso la seguente funzione in zsh:

ununzip () {
    rm -r $(unzip -l $1 | grep -v 'Archive:' | \
    grep '[/.]' | sed 's![^a-zA-Z]([a-zA-Z./])!\1!')
}

Vale a dire la sostituzione del comando per rimuovere tutti i file nell'output pulito di unzip -l.

tar tvf potrebbe essere usato in modo simile.

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.