Alle Dateien im Verzeichnis komprimieren?

483

Gibt es eine Möglichkeit, alle Dateien in einem bestimmten Verzeichnis mit dem zipBefehl zu komprimieren ? Ich habe von der Verwendung *.*gehört, möchte aber, dass es auch für Dateien ohne Dateierweiterung funktioniert.

tkbx
quelle
2
Haben Sie versucht, von Ihrem gewünschten Verzeichnis aus eine Ebene nach oben zu navigieren und dies zu tun zip myarch.zip mydir/*?
Joseph R.
13
oder besserzip -r myarch.zip mydir/*
Adam
25
oder besserzip -r myarch.zip mydir
ctrl-alt-delor
*.*bedeutet jede Datei mit einem Punkt. In cp / m und dos hatten alle Dateien einen Punkt, und Sie mussten ihn eingeben (was nicht möglich war *). Daher kamen die Leute, um *.*alle Dateien zu sehen. Schließlich fügte Microsoft lange Dateinamen hinzu, die null oder mehr Punkte enthalten könnten. Um eine Datei mit einem Punkt in Windows zu finden, müssen Sie Folgendes eingeben *.*.*.
Strg-Alt-Delor

Antworten:

705

Sie können nur verwenden *; es besteht keine Notwendigkeit dafür *.*. Dateierweiterungen sind unter Unix nichts Besonderes. *Stimmt mit keinem oder mehreren Zeichen überein, einschließlich eines Punkts. Es passt also foo.png, denn das sind null oder mehr Zeichen (sieben, um genau zu sein).

Beachten Sie, dass *Dateien, die mit einem Punkt beginnen , standardmäßig nicht übereinstimmen (was auch nicht der Fall ist *.*). Das ist oft was du willst. Wenn nicht, in bash, wenn Sie shopt -s dotglobes wollen (aber immer noch ausschließen .und ..). Andere Shells haben andere (oder gar keine) Möglichkeiten, Punktdateien einzuschließen.

Alternativ gibt es zipauch eine -r(rekursive) Option, um ganze Verzeichnisbäume auf einmal zu erstellen (und sich nicht um das Dotfile-Problem kümmern zu müssen):

zip -r myfiles.zip mydir

Wo mydirist das Verzeichnis, in dem sich Ihre Dateien befinden? Beachten Sie, dass die erstellte Zip-Datei die Verzeichnisstruktur sowie die Dateien enthält. Wie Peterph in seinem Kommentar ausführt, wird dies normalerweise als eine gute Sache angesehen: Wenn Sie die Zip-Datei extrahieren, werden alle extrahierten Dateien in einem Unterverzeichnis gespeichert.

Sie können zip auch anweisen, die Pfade nicht mit der Option -j/ zu speichern --junk-paths.

Der zipBefehl wird mit einer Dokumentation geliefert, die Sie über alle (vielen) Optionen informiert. Geben Sie ein man zip, um diese Dokumentation anzuzeigen. Dies gilt nicht nur für zip. Auf diese Weise erhalten Sie Dokumentation für die meisten Befehle.

derobert
quelle
9
Vielleicht möchten Sie hinzufügen, dass es eine gute Praxis ist, alles im Archiv in einem Verzeichnis der obersten Ebene zu speichern, damit das aktuelle Verzeichnis beim Extrahieren nicht verunreinigt wird.
Peterph
@peterph fertig. Obwohl dies in zip-Dateien weniger eine Konvention ist als in z. B. Tarfiles, fürchte ich.
Derobert
leider ja. Vermutlich aufgrund des Windows-Erbes von Drag'n'Drop auf den Desktop und des Linux-Erbes der Arbeit mit Quellcodes.
Peterph
2
*Beachten Sie, dass beim Shell-Globbing keine Punktdateien (dh Dateinamen, die mit beginnen .) enthalten sind. Dies ist ein weiterer Vorteil beim Zippen des gesamten Verzeichnisses nach Namen.
Mrb
Die Verwendung von -r schließt jedoch das Verzeichnis selbst ein. Wäre nicht * enthalten .und ..?
tkbx
11

In meinem Fall wollte ich jede Datei in ein eigenes Archiv packen, also habe ich folgendes (in zsh) gemacht:

$ for file in *; do zip ${file%.*}.zip $file; done
Radon Rosborough
quelle
1
Es gibt kein mkvhier? Auch hier ist nichts besonders zshspezifisch. Sie sollten jede Variable, die einen Dateinamen enthält, korrekt in Anführungszeichen setzen. Verwenden Sie also zip "${file%.*}.zip" "$file"die doppelten Anführungszeichen um beide Variablen.
Tripleee
1
@tripleee Erstens danke, dass du auf meinen fehlerhaften Verweis auf hingewiesen hast mkv. Zweitens ist das Zitieren von Argumenten im zshGegensatz zu in unnötig bash. Deshalb habe ich angegeben, dass dies ein Befehl für war zsh.
Radon Rosborough
Wenn Sie das letzte Semikolon durch ein kaufmännisches Und ersetzen, wird dies möglicherweise erheblich beschleunigt (wenn die Anzahl der Dateien im Verzeichnis angemessen ist ...). Ansonsten find . -type f -maxdepth 1 -print0|xargs -r0 -n1 -P64 -I{} bash -c 'f="{}"; zip "${f%.*}.zip" "$f"'(mit -Pje nach CPU angepassten Threads ...) (Viele GNU-Abhängigkeiten ...)
Gert van den Berg
5

Eine andere Möglichkeit wäre, find und xargs zu verwenden: (Dies könnte ein "." - Verzeichnis in der Zip-Datei enthalten, das aber trotzdem korrekt extrahiert werden sollte. Bei meinem Test hat zip den Punkt vor der Komprimierung entfernt.) find . -type f -exec zip zipfile.zip {} +

(Das +kann durch ersetzt werden, \;wenn Ihre Version von finddas +Ende für exec nicht unterstützt . Es wird jedoch langsamer sein ...)

Dies schließt standardmäßig alle Unterverzeichnisse ein. Auf GNU find -maxdepthlässt sich das verhindern.

Gert van den Berg
quelle
(Im Gegensatz zu den verwendeten Lösungen enthält *dies Punktdateien und fällt nicht um, wenn sich zu viele Dateien in einem Verzeichnis befinden.)
Gert van den Berg
1

Eine andere (langsame) Methode, um dies zu tun (die jeweils eine Datei zur Zip hinzufügt):

for f in * .[^.]*; do
    [ -r "$f" ] || continue # Skip directories or non-existant files (Probably ".[^.]*" if directory has no dotfiles). Using -e will allow directories to be used as well
    zip zipfile.zip "$f" # If directories are included, you probably want to add -r
done

Dies hat die dotfile-Probleme *( Problemumgehung hinzugefügt) und würde zip einmal für jede Datei starten und sie dem Archiv hinzufügen. In bashwürde es mit einer großen Menge von Dateien umgehen.

Es wäre langsamer als die meisten anderen Methoden, ist aber relativ einfach.

Gert van den Berg
quelle
1
Ich würde sagen, dies ist weniger einfach als die akzeptierte Antwort und langsamer, was die Frage aufwirft: "Warum sollte jemand das tun?". Wenn Sie diese Frage beantworten können, empfehle ich, dass Sie diesen Kontext in Ihre Antwort aufnehmen, andernfalls halte ich es für eine schlechte Antwort auf eine alte Frage, die bereits eine gute Antwort hat.
Centimane
@ Centimane: Ich beachte die Einschränkungen. Ich denke, das hat einen pädagogischen Wert. (Wenn Sie keine Verzeichnisse überspringen, ist das ganz einfach). Wenn Sie eine viel schnellere Antwort mit einem (Standard-) externen Tool wünschen, wird dies in meiner anderen Antwort behandelt . (Wenn die Behandlung der Punktedateien entfernt ist (was die Korrektheit beeinträchtigt, ohne dass dies in der Frage erwähnt wird), finde ich das ziemlich elegant):for f in *; do zip zip.zip "$f"; done
Gert van den Berg
1
Beachten Sie, dass die akzeptierte Antwort keinen externen Befehl verwendet und schneller wäre. In welchem ​​Szenario wäre diese Antwort nützlich?
Centimane,
@Centimane Mit tar, wenn es mehr Dateien gibt, als Bash als Parameter übergeben kann. (find + xargs sind besser, denn Schleifen sind einfacher ...). Es ist eine (eindeutige) Antwort auf die Frage. Es ist sicherlich nicht die optimale Antwort. (Nicht optimale Antworten können für ähnliche Probleme immer noch nützlich sein, wenn jemand eine etwas andere Situation hat - z. B. wenn er möchte, dass eine TAR-Datei Verzeichnisse enthält)
Gert van den Berg