Ich habe eine Liste von Verzeichnissen, die ich archivieren möchte. Aber manchmal existieren sie nicht alle.
Ich möchte in der Lage sein, ein Archiv zu erstellen, indem ich eine Liste von Verzeichnissen bereitstelle. Dabei werden nur die vorhandenen archiviert und fehlende Verzeichnisse ignoriert. (sollte aber trotzdem fehlschlagen, wenn keine Verzeichnisse vorhanden sind)
Dies ist nützlich für mich, da ich eine kontinuierliche Integration durchführe und einige der Prozesse bestimmte Artefakte erstellen, die ich für die Zukunft in einem Archiv behalten möchte. Ich kenne alle möglichen Pfade, die erstellt werden können, bin mir aber nicht immer sicher, welche erstellt werden.
Angenommen, die möglichen Pfade sind: here_is_a_dir
here_is_another_one
yet_another_dir
Normalerweise erstelle ich das Archiv mit dem folgenden Befehl:
tar -czf archive.tgz here_is_a_dir here_is_another_one yet_another_dir
Was natürlich fehlschlägt, wenn eines der Verzeichnisse fehlt.
Im Idealfall sollte es sich um einen einfachen Befehl handeln, für den kein Skript erforderlich ist. (Insbesondere ist nur in meiner Umgebung sh
verfügbar, daher kann ich keine ausgefallenen Shells wie bash
oder andere verwenden, aber das ist spezifisch für meine Umgebung und könnte sich in Zukunft ändern. Antworten mit anderen Shells sind wahrscheinlich auch gut, denke ich. )
quelle
sh
steht mir momentan zur Verfügung. Dies ist jedoch eine Einschränkung, die sich nur auf meine spezifische Situation auswirkt. Antworten mit anderen Shells sind meiner Meinung nach immer noch gute Antworten.cpio
.Antworten:
Die Verwendung der Ausgabe von
ls
ist im Allgemeinen unklug und unsicher. Denken Sie daran, dass sowohl Leerzeichen als auch Zeilenumbrüche und andere Shell-Metazeichen gültige Zeichen in einem Datei- oder Verzeichnisnamen sind. In vielen Fällen ist es möglich, dieses Problem zu umgehen. Dies ist jedoch in der Regel aufwändiger als die Verwendung des richtigen Tools für den Job (dhfind
).Verwenden Sie
find
stattdessen. Zum Beispiel:Dadurch wird eines der übereinstimmenden Verzeichnisse (
-type d
) im aktuellen Verzeichnis (.
) gefunden und als Argument für dentar
Befehl verwendet. Das\(
zu\)
ist ein Ausdruck, bei dem jeder der Unterausdrücke zusammen mit ODER verknüpft wird-o
(standardmäßig sind die Prädikate von find UND-verknüpft). dh es lautet "maxdepth 1 AND type directory AND (dir1 OR dir2 OR dir3)".Beachten Sie, dass ohne die Klammern zum Erzwingen der Priorität "maxdepth 1 AND type type AND dir1 OR (dir2 OR dir3)" interpretiert wird, wodurch nicht die vollständige Liste aller vorhandenen Verzeichnisse zurückgegeben wird. Meistens würde es entweder nichts oder nur dir3 zurückgeben, je nachdem, ob dir1 existiert oder nicht.
Wenn Sie möchten, dass die Unterverzeichnisse irgendwo unter dem aktuellen Verzeichnis gefunden werden, löschen Sie das
-maxdepth 1
Argument.Wenn bei den Verzeichnisübereinstimmungen die Groß- und Kleinschreibung nicht berücksichtigt werden soll, verwenden Sie
-iname
stattdessen-name
. Beachten Sie, dass das Argument für-name
oder-iname
ein Muster anstelle einer festen Zeichenfolge sein kann. Dies ist nützlich, wenn die gewünschten Verzeichnisnamen sehr ähnlich sind. z.BDas
-exec ....
funktioniert sehr ähnlich wie Rohrleitungen,xargs
ist aber eingebautfind
. In der Tat könnten Sie verwenden,xargs
wenn Sie möchten, indem Sie alles von nun-exec
an durch ersetzen-print0 | xargs -0 -r tar cfz archive.tgz
. z.B(Dies verwendet ein NUL-Zeichen als Ausgabetrennzeichen, daher ist die Verwendung mit Dirnamen, die Leerzeichen usw. enthalten, genauso sicher wie die Verwendung
-exec
. Die-r
Option weist xargs an, nichts zu tun, wenn keine Eingabe erfolgt.)quelle
xargs
Variante kann es erwähnenswert sein, dass-r
es sich um eine GNU-Erweiterung handelt (laut Manpage).find
Versionen unterstützen-print0
, aber Sie müssen ziemlich weit in die Geschichte zurückgehen (Paläo-Unix :-), um eine zu finden, die dies nicht tut. Übrigens habe ich bemerkt, dassbusybox
dies in anderen Kommentaren hier erwähnt wurde -man busybox
zeigt, dass es unterstütztxargs -r
. ebenso wie die Version von freebsd vonxargs
(eine Null-Option, die eigentlich nicht benötigt wird, standardmäßig nur für die Kompatibilität mit GNU).Mit
zsh
:Das POSIX-Äquivalent (obwohl weder POSIX-Befehle
tar
nochxz
POSIX-Befehle vorhanden sind) wäre etwa:quelle
Wenn Sie bash verwenden können, dann mit erweitertem globbing (
extglob
):Und wenn einer oder mehrere davon existieren:
(Ich habe verwendet,
set -x
damit Sie die Ergebnisse der Glob-Erweiterung sehen können.)quelle
bash
steht mir in dieser umgebung leider nicht zur verfügung. Aber die Antwort ist immer noch richtig und bekommt meine +1Dies kann relativ einfach durchgeführt werden, indem
ls
eine Liste vorhandener Verzeichnisse erstellt und dannxargs
in dentar
Befehl weitergeleitet wird.Lösung:
ls -d here_is_a_dir here_is_another_one yet_another_dir 2> /dev/null | xargs tar -czf archive.tgz
Nervenzusammenbruch:
ls -d
Listen Sie nur Verzeichnisse aufhere_is_a_dir here_is_another_one yet_another_dir
die Liste der Verzeichnisse, nach denen gesucht werden soll2> /dev/null
Leite den stderr nach / dev / null, damit wir nur die stdout-Ausgabe erhalten (keine fehlenden Verzeichnisse).| xargs
wandelt die Liste der vorhandenen Verzeichnisse aus dem vorherigen Befehl in Argumente umtar -czf archive.tgz
Erstellen Sie ein Archiv mit den Argumentenquelle
tar -czf archive.tgz
für jedes Verzeichnis separat gestartet wird. In diesem Fall hätten Sie nur das letzte Verzeichnis im Archiv.Eine, die nur mit POSIX sh (
tar.sh
) funktionieren sollte :Prüfung:
quelle
Wenn Sie pax haben , können Sie damit filtern, was im Archiv enthalten ist. Pax wird von POSIX als Ersatz für das historisch vielfältige cpio und tar beauftragt, aber viele Unix-Varianten haben sich seiner Einführung widersetzt, und insbesondere BusyBox hat es nicht.
Pax hat eine Funktion zum Ausschließen von Dateien, obwohl diese in der Beschreibung eher versteckt ist. Sie können Dateien mit umbenennen
-s
. Wenn Sie eine Datei in die leere Zeichenfolge umbenennen, wird sie ausgeschlossen. Bei mehreren-s
Optionen gilt für jede die erste Übereinstimmung, und Umbenennungsfilter-s
werden übersprungen. Auf diese Weise können Sie eine Reihe von Einschluss- / Ausschlussregeln erstellen, ähnlich wie bei rsync . Eine Einschlussregel in der Pax-Syntax lautet-s'!REGEX!&!'
(in sich selbst umbenennen) und eine Ausschlussregel lautet-s'!REGEX!!'
(in leer umbenennen).BSD-Teer hat eine ähnliche
-s
Option. Auf der anderen Seite haben GNU-Teer und BusyBox-Teer keine Möglichkeit, dies zu tun, einschließlich Gymnastik.quelle
Am einfachsten ist es wahrscheinlich
quelle
Wenn Ihre Version dies
tar
unterstützt, erstellen Sie eine leere TAR-Datei und hängen Sie sie bei Bedarf an, indem Sie-r
statt-c
quelle