Wie entpacke ich, de-tar -xvf - de-unarchive in einem chaotischen Ordner?

14

Normalerweise lösche ich die Archivierung von Dingen, $ mkdir newFolder; $ mv *.zip newFolder; $ cd newFolder; $unzip *.zipaber manchmal werde ich faul und mache es einfach in einem beliebigen Ordner, $ unzip *.zipdamit ich von Zeit zu Zeit mit anderen Inhalten durcheinander komme . Ich werde hier einige Methoden auflisten - einige Archivversionen haben sicherlich beschissene Flaggen, während andere spartanischer sind, ich interessiere mich mehr für letztere.

Einige Wege, um die Archivierung aufzuheben, gibt es andere?

  1. $ find . -anewer fileThatExistedBeforeUnarchieving -ok rm '{}' \;Schwächen sind, dass es die Verzeichnisse *.zipauflistet, so dass Sie langsam -ok, langsam mit vielen *.zipÜbereinstimmungen verwenden müssen und aus irgendeinem Grund nicht alles zu finden scheint, was extrahiert wurde.

  2. Wenn kleine Menge von extrahierten Dateien, eins nach dem anderen, langsam, umständlich und fehleranfällig.

  3. Wenn ich sicherstellen will, dass der Inhalt des Archivs tatsächlich ein Ordner ist, überprüfe ich ihn manchmal mit $ unzip -l *.bsd, zumindest in obsds Entpack-Version.

Wenn Sie sich auf bestimmte Archivierungswerkzeuge beziehen, geben Sie diese gegebenenfalls an. Halten Sie es einfach - ich bin mehr an den Möglichkeiten interessiert, wie Sie es tun, als an einem einzigen Tool.

Rui F Ribeiro
quelle
1
Siehe auch Speicherort für versehentliches Extrahieren - Bereinigen?
Gilles 'SO - hör auf, böse zu sein.'
Hier ist ein Skript, mit dem ich das mkdir; unzipZeug automatisiere, damit ich nie zu faul bin, es zu tun! svn.mikelward.com/svn/scripts/untar
Mikel
2
Siehe diese verwandte Frage und Antworten: unix.stackexchange.com/questions/5123/…
alex

Antworten:

11

Namentlich

Sie können die Liste der Dateien im Archiv generieren und löschen, was bei Archiven wie unzip oder 7z, die keine Option zum Generieren einer einfachen Liste von Dateinamen haben, ärgerlich ist. Selbst mit tar wird davon ausgegangen, dass die Dateinamen keine Zeilenumbrüche enthalten.

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

Anstatt die Dateien zu entfernen, können Sie sie an den gewünschten Ort verschieben.

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

FUSE verwenden

Anstatt von externen Tools abhängig zu sein, können Sie (bei den meisten Unices) FUSE verwenden , um Archive mit normalen Dateisystembefehlen zu bearbeiten.

Sie können Fuse-zip verwenden, um einen Blick in ein Zip zu werfen, es mit zu extrahieren cp, seinen Inhalt mit aufzulisten findusw.

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 erstellt eine Ansicht Ihrer gesamten Verzeichnishierarchie, in der allen Archiven ein Verzeichnis zugeordnet ist (derselbe Name mit # am Ende), das den Archivinhalt zu enthalten scheint.

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

Nach Datum

Angenommen, es gibt keine anderen Aktivitäten in derselben Hierarchie als Ihre Extraktion, können Sie die extrahierten Dateien anhand ihrer letzten C-Zeit ermitteln . Wenn Sie die ZIP-Datei gerade erstellt oder verschoben haben, können Sie sie als Cutoff verwenden. Andernfalls verwenden Sie ls -lctr, um eine geeignete Abschaltzeit zu bestimmen. Wenn Sie sicherstellen möchten, dass die Reißverschlüsse nicht entfernt werden, gibt es keinen Grund für eine manuelle Genehmigung: Sie können sie finddurchaus ausschließen. Hier sind Beispielbefehle mit zsh oder find; Beachten Sie, dass die -cminund -cnewer-Primäre nicht in POSIX, sondern unter Linux (und anderen Systemen mit GNU find), * BSD und OSX vorhanden sind.

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

Mit GNU find, FreeBSD und OSX können Sie die Cutoff-Zeit auch festlegen, indem Sie eine Datei erstellen und touchderen mtime auf die Cutoff-Zeit setzen.

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

Anstatt die Dateien zu entfernen, können Sie sie an den gewünschten Ort verschieben. Hier ist ein Weg mit GNU / * BSD / OSX zu finden, Verzeichnisse im Ziel zu erstellen, wie benötigt.

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

Zsh-Äquivalent (fast: dieses gibt die gesamte Verzeichnishierarchie wieder, nicht nur die Verzeichnisse, die Dateien enthalten):

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

Achtung, ich habe die meisten Befehle in dieser Antwort nicht getestet. Überprüfen Sie immer die Liste der Dateien, bevor Sie sie entfernen ( echozuerst ausführen , dann, rmwenn es in Ordnung ist).

Gilles 'SO - hör auf böse zu sein'
quelle
Ich bin heute endlich auf dieses Problem gestoßen. Als root! Am Ende habe ich eine Kombination aus "Nach Name" und "Nach Datum" verwendet
phunehehe 31.01.11
1

Ich fühle mich sowieso dumm, ich habe mir am Kopf gekratzt, um dieses Skript zu schreiben, als ich ein ähnliches Problem hatte. Ich habe cpiomit der -itFlagge eine Liste der Dateien abgerufen. Sie können gleichwertige Befehle für andere Archivierer verwenden. Der knifflige Teil ist, dass das cpio-Archiv von einem initrd stammt, in das ich extrahiert habe /, sodass viele Ordner und Dateien denselben Namen haben wie in einem funktionierenden System. Zum Glück hat cpio keine meiner vorhandenen Dateien überschrieben. Ich benutze eine Zeitüberprüfung, um sicherzustellen, dass nichts gelöscht wird, was vor dem falschen Befehl vorhanden war.

#! /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
phunehehe
quelle
0

Wie wäre es, die Liste der Dateien im Archiv zu füttern xargs rm?

Das wäre tar -tf tarbomb.tar | xargs rmoder unzip --list zipbomb.zip | xargs rm.

Alex
quelle
2
Die angegebenen Befehle funktionieren im Allgemeinen nicht, und dies ist gefährlich, da Sie Dateien entfernen. xargserwartet, dass seine Eingabe in einer eigenartigen Weise zitiert wird, finddie nicht produziert. Verwenden Sie xargs -I rm {}diese Option, damit xargs stattdessen ein Element pro Zeile verarbeitet. Welche Implementierung haben Sie für den Befehl unzip? Meins (Debian / Ubuntu) hat nicht --listnur -l, und es druckt nicht nur Dateinamen, so dass zusätzliche Verarbeitung erforderlich ist.
Gilles 'SO - hör auf, böse zu sein.'
@ Gilles: 1) Ja, es ist gefährlich, aber da wir vermutlich die Originaldateien überschrieben haben, sind sie bereits weg. 2) Ich habe nicht darüber gesprochen find. 3) Sie haben Recht unzip, ich habe nicht getestet und es scheint keine Option für eine nicht dekorierte Auflistung zu geben. Nein auch --listauf meinem Ubuntu - ich habe es nur nicht getestet.
Alex
Sorry über die Dosen-Reaktion, Ersatz tar -tfür find. Aber meine anderen Punkte stehen. Es besteht die reale Gefahr, dass durch Ihren Befehl eine nicht verwandte Datei gelöscht wird.
Gilles 'SO- hör auf böse zu sein'
tar -tf tarbomb.tarGibt einen Dateinamen pro Zeile aus, so dass Sie dies tun können tar -tf tarbomb.tar | while IFS=$'\n' read -r filename; do rm "$filename"; done.
Mikel
0

Nicht wirklich das, wonach Sie gefragt haben, aber wie wäre es, stattdessen ein Skript zum Entpacken aller Dateien zu verwenden?

unzip *.zip

Auf diese Weise gelangt die Ausgabe jeder Datei in ein eigenes Verzeichnis.

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

Ich benutze die folgende Funktion in zsh:

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

Dh Befehlsersetzung, um alle Dateien in der bereinigten Ausgabe von zu entfernen unzip -l.

tar tvf könnte in ähnlicher Weise verwendet werden.

Edd Steel
quelle