Ich habe ein Verzeichnis mit 10144911 Dateien. Bisher habe ich Folgendes versucht:
for f in ls; do sed -i -e 's/blah/blee/g' $f; done
Ich habe meine Muschel ls
zerschmettert , die ist in einer Tilda, aber ich kann nicht herausfinden, wie ich eine machen soll.
ls | xargs -0 sed -i -e 's/blah/blee/g'
Zu viele Argumente für sed
find . -name "*.txt" -exec sed -i -e 's/blah/blee/g' {} \;
Konnte kein Gedächtnis mehr haben
Haben Sie noch weitere Ideen, wie Sie einen solchen Befehl erstellen können? Die Dateien müssen nicht miteinander kommunizieren. ls | wc -l
scheint zu funktionieren (sehr langsam), also muss es möglich sein.
sed
für jede Datei vermeiden könnten . Ich bin nicht sicher, ob es eine Möglichkeit gibt, eine Reihe von Dateien zu öffnen, zu bearbeiten, zu speichern und zu schließensed
. Wenn es auf Geschwindigkeit ankommt, können Sie ein anderes Programm verwenden, z. B. Perl oder Python.sed
ist wahrscheinlich schneller als der Startpython
oderperl
auch, es sei denn, Sie tun alles in diesem Interpreter.Antworten:
Probieren Sie es aus:
Pro Aufruf von wird nur ein Dateiname eingegeben
sed
. Das wird das Problem "zu viele Argumente für sed" lösen. Die-P
Option sollte das gleichzeitige Verzweigen mehrerer Prozesse ermöglichen. Wenn 0 nicht funktioniert (es sollen so viele wie möglich ausgeführt werden), versuchen Sie es mit anderen Zahlen (10 - 100 - die Anzahl der Kerne, die Sie haben?), Um die Anzahl zu begrenzen.quelle
find . -name \*.txt -print0
vermieden werden , dass die Shell den Glob erweitert und versucht, Platz für 10 Millionen zu findende Argumente zu reservieren .Ich habe diese Methode (und alle anderen) an 10 Millionen (leeren) Dateien mit den Namen "Hallo 00000001" bis "Hallo 10000000" (14 Byte pro Name) getestet.
UPDATE: Ich habe jetzt einen Quad-Core- Lauf in die
'find |xargs'
Methode aufgenommen (immer noch ohne 'sed'; nur echo> / dev / null).Hier ist eine Zusammenfassung der Ergebnisse der angegebenen Antworten, wenn sie mit den oben genannten Testdaten verglichen wurden. Diese Ergebnisse betreffen nur die grundlegenden Gemeinkosten. dh "sed" wurde nicht aufgerufen. Der Sed-Prozess wird mit ziemlicher Sicherheit am zeitaufwändigsten sein, aber ich dachte, es wäre interessant zu sehen, wie die bloßen Methoden verglichen werden.
Dennis '
'find |xargs'
Methode, bei der ein einzelner Kern verwendet wurde, dauerte * 4 Stunden 21 Minuten ** länger als diebash array
Methode bei einemno sed
Durchlauf ... Der Mehrkernvorteil von' find 'sollte jedoch die Zeitunterschiede ausgleichen, die angezeigt werden, wenn sed angefordert wird Verarbeiten der Dateien ...quelle
Eine weitere Möglichkeit für den rundum sicheren Fund :
quelle
Dies ist meistens nicht zum Thema, aber Sie könnten verwenden
Der Hauptvorteil hier (gegenüber
... xargs ... -I {} ... sed ...
) ist die Geschwindigkeit: Sie vermeiden es,sed
10 Millionen Mal aufzurufen . Es wäre noch schneller, wenn Sie die Verwendung von Python vermeiden könnten (da Python relativ langsam ist), daher ist Perl möglicherweise die bessere Wahl für diese Aufgabe. Ich bin nicht sicher, wie ich das Äquivalent bequem mit Perl machen soll.Dies funktioniert so, dass
xargs
Python mit so vielen Argumenten aufgerufen wird, wie auf eine einzelne Befehlszeile passen, und dies so lange, bis die Argumente (die von bereitgestellt werdenls -f *.txt
) ausgehen. Die Anzahl der Argumente für jeden Aufruf hängt von der Länge der Dateinamen und einigen anderen Dingen ab. Diefileinput.input
Funktion liefert aufeinanderfolgende Zeilen aus den Dateien, die in den Argumenten jedes Aufrufs angegeben sind, und dieinplace
Option weist sie an, die Ausgabe magisch zu "fangen" und sie zum Ersetzen jeder Zeile zu verwenden.Beachten Sie, dass die String-
replace
Methode von Python keine regulären Ausdrücke verwendet. Wenn Sie diese brauchen, müssen Sieimport re
und verwendenprint re.sub(line, "blah", "blee")
. Es handelt sich um Perl-kompatible RegExps, eine Art stark verstärkter Versionen derjenigen, mit denen Sie arbeitensed -r
.bearbeiten
Wie Akira in den Kommentaren erwähnt, würde die Originalversion, bei der ein Glob (
ls -f *.txt
) anstelle desfind
Befehls verwendet wird, nicht funktionieren, da Globs von der Shell (bash
) selbst verarbeitet werden. Dies bedeutet, dass vor der Ausführung des Befehls 10 Millionen Dateinamen in die Befehlszeile eingefügt werden. Dies wird so gut wie garantiert die maximale Größe der Argumentliste eines Befehls überschreiten. Sie könnenxargs --show-limits
für systemspezifische Informationen dazu verwenden.Die maximale Größe der Argumentliste wird ebenfalls berücksichtigt
xargs
, wodurch die Anzahl der Argumente, die an jeden Aufruf von Python übergeben werden, entsprechend dieser Grenze begrenzt wird. Daxargs
Python noch einige Male aufgerufenos.path.walk
werden muss, spart Ihnen Akiras Vorschlag , die Dateiliste zu erstellen, wahrscheinlich etwas Zeit.quelle
os.path.walk()
?.
und zu ersetzen..
. Natürlich gibt es auch andere Möglichkeiten, dies zu tun (zBfind
), aber ich versuche, mich so genau wie möglich an das zu halten, was das OP versteht. Dies ist auch der Grund für die Nichtverwendungos.path.walk
.os.path.walk
ganz leicht verstehen wird .Versuchen:
quelle
ls -f
wäre besser; Möchten Sie wirklich darauf warten,stat()
dass so viele Dateien sortiert werden?