Ich habe gerade eine Frage gestellt, die sich darauf bezieht, wie ich die Dateien einer bestimmten Erweiterung zählen kann. Nun möchte ich cp
diesen Dateien einen neuen hinzufügen dir
.
Ich versuche,
cp *.prj ../prjshp/
und
cp * | grep '\.prj$' ../prjshp/
aber sie geben den gleichen Fehler,
bash: / bin / cp: Argumentliste zu lang
Wie kopiere ich sie?
command-line
files
Sam007
quelle
quelle
Antworten:
cp *.prj ../prjshp/
ist der richtige Befehl, aber in seltenen Fällen stößt er auf eine Größenbeschränkung. Der zweite Befehl, den Sie ausprobiert haben, ergibt keinen Sinn.Eine Methode besteht darin,
cp
die Dateien in Blöcken auszuführen . Derfind
Befehl weiß, wie das geht:find
Durchläuft das aktuelle Verzeichnis und die Verzeichnisse darunter rekursiv.-maxdepth 1
bedeutet, bei einer Tiefe von 1 anzuhalten, dh nicht in Unterverzeichnisse zurückzukehren.-name '*.prj'
bedeutet, nur auf die Dateien zuzugreifen, deren Name mit dem angegebenen Muster übereinstimmt. Beachten Sie die Anführungszeichen um das Muster: Es wird vomfind
Befehl und nicht von der Shell interpretiert .-exec … {} +
bedeutet, den angegebenen Befehl für alle Dateien auszuführen. Bei Bedarf wird der Befehl mehrmals aufgerufen, wobei darauf geachtet wird, dass das Befehlszeilenlimit nicht überschritten wird.mv -t ../prjshp
verschiebt die angegebenen Dateien in../prjshp
. Die-t
Option wird hier aufgrund einer Einschränkung desfind
Befehls verwendet: Die gefundenen Dateien (symbolisiert durch{}
) werden als letztes Argument des Befehls übergeben. Sie können das Ziel nicht danach hinzufügen.Eine andere Methode ist zu verwenden
rsync
.rsync -r … . ../prjshp
kopiert das aktuelle Verzeichnis nach../prjshp
rekursiv.--include='*.prj' --exclude='*'
bedeutet, dass Dateien kopiert werden, die übereinstimmen,*.prj
und alles andere ausgeschlossen wird (einschließlich Unterverzeichnissen, sodass.prj
Dateien in Unterverzeichnissen nicht gefunden werden).quelle
cp * | grep '\.prj$' ../prjshp/
keinen Sinn, kann aber syntaktisch gültig sein, wenn er*
sich zu einer Liste von Dateien erweitert, wobei der letzte ein Verzeichnis (akacp SOURCE1 SOURCE2....DEST
) ist. Die Pipe macht sicher keinen Sinn, bleibt aber auch syntaktisch gültig, was die Shell betrifft -dup()
die Dateideskriptoren sind in Ordnung, nur, dass das Leserende der Pipe keine Daten erhält, weilcp
es keine schreibt .Dieser Befehl kopiert die Dateien nacheinander und funktioniert auch dann, wenn es zu viele gibt
*
, um sie zu einem einzigencp
Befehl zu erweitern :quelle
Bei
Argument list too long
Fehlern sind drei wichtige Punkte zu beachten :Die Länge der Befehlszeilenargumente ist durch eine
ARG_MAX
Variable begrenzt , die laut POSIX-Definition "... [m] maximale Länge der Argumente für die exec-Funktionen einschließlich Umgebungsdaten" (Hervorhebung hinzugefügt) ist. Das heißt, wenn die Shell ein non ausführt -built-it-Befehl, muss einen von aufrufenexec()
, um den Befehlsprozess zu erzeugen, und genau hierARG_MAX
kommt es an. Außerdem spielt der Name oder der Pfad zum Befehl selbst (zum Beispiel/bin/echo
) eine Rolle.Shell-Befehle werden von der Shell ausgeführt. Dies bedeutet, dass die Shell keine
exec()
Funktionsfamilie verwendet und daher vonARG_MAX
Variablen nicht betroffen ist.Bestimmte Befehle, wie z. B.
xargs
undfind
kennenARG_MAX
Variablen und führen Aktionen unter dieser Grenze wiederholt ausAus den obigen Punkten und wie in Kusalanandas hervorragender Antwort auf verwandte Fragen gezeigt,
Argument list too long
kann dies auch auftreten, wenn die Umgebung groß ist. In Anbetracht der Tatsache, dass die Umgebung jedes Benutzers variieren kann und die Argumentgröße in Byte relevant ist, ist es schwierig, eine einzige Anzahl von Dateien / Argumenten zu finden.Wie gehe ich mit solchen Fehlern um?
Das Wichtigste ist, sich nicht auf die Anzahl der Dateien zu konzentrieren, sondern darauf, ob der Befehl, den Sie verwenden möchten, eine
exec()
Funktionsfamilie und tangential - den Stapelspeicherplatz - umfasst.Verwenden Sie Shell-Built-Ins
Wie bereits erwähnt, sind die Shell-Built-Ins unempfindlich gegen
ARG_MAX
Einschränkungen, wie z. B.for
Loop,while
Loop, Built-Inecho
und Built-In.printf
All diese sind ausreichend leistungsfähig.Bei verwandten Fragen zum Löschen von Dateien gab es eine Lösung als solche:
Beachten Sie, dass hierfür die integrierte Shell verwendet wird
printf
. Wenn wir das Externe anrufenprintf
, wird dies einbeziehenexec()
und daher mit einer großen Anzahl von Argumenten scheitern:Bash-Arrays
Laut einer Antwort von jlliagre
bash
gibt es keine Einschränkungen für Arrays. Daher können auch Arrays von Dateinamen erstellt und Slices pro Schleifeniteration verwendet werden, wie in der Antwort von danjpreron gezeigt :Dies hat jedoch die Einschränkung, bash-spezifisch und nicht POSIX-spezifisch zu sein.
Erhöhen Sie den Stapelplatz
Manchmal kann man die Menschen sehen , deuten darauf hin , Erhöhung der Stapelspeicher mit
ulimit -s <NUM>
; Unter Linux beträgt der ARG_MAX-Wert 1/4 des Stapelspeichers für jedes Programm, was bedeutet, dass durch Erhöhen des Stapelspeichers der Speicherplatz für Argumente proportional erhöht wird.Laut der Antwort von Franck Dernoncourt , der das Linux Journal zitiert, kann man den Linux-Kernel auch mit einem höheren Wert für maximale Speicherseiten für Argumente neu kompilieren. Dies ist jedoch mehr Arbeit als nötig und eröffnet das Potenzial für Exploits, wie im zitierten Artikel im Linux Journal angegeben.
Vermeiden Sie Muscheln
Eine andere Möglichkeit ist die Verwendung von
python
oderpython3
die standardmäßig mit Ubuntu kommen. Das folgende Python + Here-Doc- Beispiel wurde von mir persönlich verwendet, um ein großes Verzeichnis mit Dateien im Bereich von 40.000 Elementen zu kopieren:Für rekursive Durchläufe können Sie os.walk verwenden .
Siehe auch:
quelle
IMHO, die optimalen Werkzeuge für die mit Horden von Dateien zu tun sind
find
undxargs
. Sehenman find
. Sehenman xargs
.find
Mit dem-print0
Schalter wird eineNUL
separate Liste von Dateinamen erstellt (Dateinamen können alle Zeichen enthalten, die ausgeführt werdenNUL
oder/
),xargs
die mit dem-0
Schalter verstanden werden.xargs
Dann wird der längste zulässige Befehl erstellt (die meisten Dateinamen, kein halber Dateiname am Ende) und ausgeführt.xargs
Wiederholt dies, bisfind
keine Dateinamen mehr angegeben werden. Laufen Siexargs --show-limits </dev/null
, um die Grenzen zu sehen.Um Ihr Problem zu lösen (und nach Überprüfung
man cp
zu finden--target-directory=
):quelle