Ich habe einen Ordner mit 2 GB Bildern und Unterordnern, die mehrere Ebenen tief sind.
Ich möchte nur N
Dateien jedes (Unter-) Ordners in einer TAR-Datei archivieren . Ich habe versucht , zu verwenden , find
dann tail
dann tar
aber konnte nicht verwalten es zur Arbeit zu kommen. Folgendes habe ich versucht (vorausgesetzt N = 10
):
find . | tail -n 10 | tar -czvf backup.tar.gz
… Was diesen Fehler ausgibt:
Cannot stat: File name too long
Was ist hier los? Denken Sie daran - auch wenn es funktioniert, denke ich, dass es nur die ersten 10 Dateien aller Ordner tariert, nicht die 10 Dateien jedes Ordners.
Wie kann ich N
Dateien von jedem Ordner erhalten? (Keine Dateireihenfolge erforderlich)
Antworten:
Wenn Sie
pax
die-0
Option unterstützen , mitzsh
:Es enthält die ersten 10 Nicht-Verzeichnisdateien jedes Verzeichnisses in der Liste, sortiert nach Dateinamen. Sie können eine andere Sortierreihenfolge auswählen, indem Sie das
om
Glob-Qualifikationsmerkmal (Reihenfolge nach Änderungszeit,Om
um die Reihenfolge umzukehren),oL
(Reihenfolge nach Länge),non
(Sortierung nach Name, aber numerisch) hinzufügen ...Wenn Sie den Standardbefehl nicht haben
pax
oder ihn nicht unterstützen,-0
aber den GNU-tar
Befehl haben, können Sie Folgendes tun:Wenn Sie nicht verwenden können
zsh
, aber Zugriff aufbash
(die Shell des GNU-Projekts) haben, können Sie Folgendes tun:Das wäre allerdings deutlich weniger effizient.
quelle
bash
ist eine andere Shell, die Shell des GNU-Projekts, die im Vergleich zu viel eingeschränkter istzsh
. Am Ende der Antwort finden Sie eine Lösung, mit der Sie arbeiten könnenbash
.Angenommen, Ihr Hauptverzeichnis ist
/tmp/dir
das Verzeichnis, aus dem Sie nur N (z. B. N = 10) Dateien jedes (Unter-) Ordners darunter in einerbackup.tar.gz
Datei archivieren möchten .Beispiel
tree
für/tmp/dir
:Code:
Dadurch wird ein
backup.tar.gz
mit 10 Dateien jedes Unterordners von unter erstellt/tmp/dir
.quelle
cd /tmp
fehlschlägt, führen Sie diesen Befehl im falschen Verzeichnis aus. Sie sollten immer den Ausgangsstatus überprüfen voncd
:cd /tmp && for...
find dir/* -type d
bedeutet, dass Sie die versteckten Verzeichnisse im aktuellen Verzeichnis nicht verarbeiten, sondern in Unterverzeichnissen. Verwendenfind dir -type d
Sie entweder oder, wenn Sie die Dateien nicht im aktuellen Verzeichnis haben möchten:find dir/. ! -name . -type d
oderfind dir ! -path dir -type d
.`find...`
bedeutet, den Operator split + glob aufzurufen (nur in zsh aufgeteilt). Hier möchten Sie den Glob-Teil nicht und nur in Zeilenumbruch teilen (obwohl Zeilenumbruch ein gültiges Zeichen in einem Dateinamen ist, sodass dieser Ansatz ohnehin fehlerhaft ist und Sie stattdessen den vonfind
s-exec
verwenden sollten).$i
nicht in Anführungszeichen setzen, müssen Sie auch den Operator split + glob aufrufen, was hier keinen Sinn ergibt. Verwenden Siefind "$i"
-I
,xargs
noch behandelt Zitat und Backslash Zeichen speziell in seinem Eingang. Es bedeutet auch, einentar
Befehl pro Zeile auszuführen, was nicht sehr effizient ist.Da die Ausgabe von
find
flach ist, wissen Sie nicht wirklich, welche Dateien zu denselben Verzeichnissen gehören, ohne die Pfade zu betrachten. Die Alternative besteht darin, mehrerefind
s (eines pro Ordner) zu verwenden, ohne die Pfade betrachten zu müssen. Das habe ich getan. Verwenden Sie Folgendes, um maximal 10 Dateien pro Unterordner zu tarieren:Dadurch werden rekursiv alle Verzeichnisse im aktuellen Ordner gefunden. Für jedes Verzeichnis werden bis zu 10 Dateien in genau diesem Ordner gefunden (
-maxdepth 1
). Sobald die gesamte Schleife beendet ist, wird dertar
Befehl für alle Dateien ausgeführt, die von der Schleife ausgegeben wurden. Ich habe auch Verzeichnis- und Ordnernamen mit Leerzeichen berücksichtigt, indem$dir
ichfind
jeden Dateinamen mit der-printf
Option in Anführungszeichen gesetzt und gedruckt habe .quelle
andere Variante
quelle
Verwenden Sie einen Hash für den Verzeichnisnamen und geben Sie den Dateinamen nur aus, wenn die Anzahl der Hashwerte unter dem Schwellenwert liegt. Z.B
quelle
Der einfachste (oder am einfachsten zu verstehende) Weg ist die Verwendung von xargs mit der
-N max-args
Option.Denken Sie daran, dass Ihre Eingabe immer etwas sein muss, für das keine Befehlszeile erforderlich
echo *.*
ist. Sie funktioniert also als Eingabe, wols *.*
dies nicht der Fall ist (zu lange Befehlszeile).find sollte in Ordnung sein, da sein Argument nur der Pfad ist, keine Liste von Dateien.
quelle
OP hat dies auch in Stackoverflow gefragt . Hier ist die Antwort, die ich dort angeboten habe.
Die Auswahl und Reihenfolge der Dateien in dieser Antwort hängt von der Reihenfolge ab ab
find
, sodass "first" hier nicht genau definiert ist. Dies kann auch von GNU Awk 4.1.0 abhängen.Bemerkungen:
find . -type f
diese Option, um sicherzustellen, dass Dateien ein führendes Verzeichnisnamenpräfix haben, damit der nächste Schritt ausgeführt werden kannawk
Befehl verfolgt solche führenden Verzeichnisnamen und gibt vollständige Pfadnamen aus, bis N (10, hier) Dateien mit demselben führenden Verzeichnis ausgegeben wurden (möglicherweise ist eine einfachereawk
Verwendung - Aufteilen von Infomuster und Programm - möglicherweise portabler).xargs
zum Aufrufentar
- wir erfassen reguläre Dateinamen, und diese müssen Argumente für diesen Archivierungsbefehl seinxargs
wird möglicherweisetar
mehrmals aufgerufen, daher hängen wir (Option -r) an ein einfaches Archiv an und komprimieren es dann, nachdem alles geschrieben wurdeMöglicherweise möchten Sie auch keine Sicherungsdatei in das aktuelle Verzeichnis schreiben, da Sie diese scannen. Aus diesem Grund schreibt dieser Vorschlag in / tmp.
quelle