Nehmen wir an, ich habe eine Datei mit dem Namen list_of_files.txt
, wobei jede Zeile einer Datei auf der Festplatte entspricht. Beispiel:
dir1/fileA.ext1
dir1/subdir1/fileB.ext2
fileC.ext3
dir2/fileD.ext4
fileE.ext5
Ich möchte aus dieser Liste eine zufällige Anzahl von Dateien auswählen und deren Wert cksum
berechnen .md5sum
Ich weiß, dass ich mit beispielsweise 3 Dateien nach dem Zufallsprinzip auswählen kann shuf -n 3 list_of_files.txt
, aber wie kann ich erreichen, dass cksum
sie als Dateinamen und nicht als Textinhalte behandelt werden?
Antwort1
Wenn Pfade in der Datei durch eine neue Zeile beendet und unverändert bereitgestellt werden, d. h. wenn jede Zeile ein separater wörtlicher Pfad ist, dann reicht eine Shell-Schleife aus:
shuf -n 3 list_of_files.txt | while IFS= read -r pth; do
cksum "$pth"
done
Es gibt auch xargs
(siehePOSIX-Spezifikationund fortgeschrittenerGNUxargs
), Es gibtGNUparallel
(NotizNicht-GNU parallel
existiertund ich beziehe mich nicht darauf). Mit dem richtigen Tool und den richtigen Optionen können Sie einem cksum
Prozess mehr als einen Pfad zuweisen (weniger cksum
Prozesse zu erzeugen ist im Allgemeinen von Vorteil) oder zwei oder mehr cksum
Prozesse parallel ausführen.
Um nur drei Dateien zu verarbeiten, bleibe ich aus Portabilitätsgründen vielleicht bei unserer Shell-Schleife; es sei denn, die Dateien sind groß und ich erwarte, dass drei cksum
parallel laufende Prozesse wesentlich schneller sind als einer cksum
gleichzeitig. Ich bin kein GNU-Experte parallel
, aber es scheint eine ganz einfache Lösung zu geben:
shuf -n 3 list_of_files.txt | parallel cksum
Standardmäßig parallel
begrenzt GNU die Anzahl gleichzeitiger Jobs durch die Anzahl der CPU-Kerne. Drei oder mehr Kerne sind heutzutage üblich, sodass der Befehl wahrscheinlich drei cksum
Prozesse parallel ausführen wird. Formal ist dies jedoch nicht portierbar. Beachten Sie auch, dass die parallele Verarbeitung von drei Dateien das parallele Lesen von drei Dateien bedeutet. E/A kann ein Engpass sein und dies kann den Nutzen paralleler Jobs verringern oder die Dinge sogar verschlimmern.
Auch dann parallel
kann es sinnvoll sein. Verwenden Sie, -j 1
um die Anzahl der Jobs auf 1 zu begrenzen:
shuf -n 3 list_of_files.txt | parallel -j 1 cksum
Die Dateien werden wie in unserer Shell-Schleife sequentiell verarbeitet, aber die Syntax ist einfacher. Im Fall unserer Shell-Schleife müssen Sie wissen, was Sie wollenIFS= read -r pth
, nicht nur read pth
; und Sie müssen wissen, dass Sie (in vielen Schalen) wollencksum "$pth"
, nicht cksum $pth
. Die Lösung mit GNU parallel
ist weniger fehleranfällig.KUSS.
Beachten Sie, xargs
dass standardmäßig Anführungszeichen und Backslashs interpretiert werden und Leerzeichen als Trennzeichen betrachtet werden. Dies shuf -n 3 list_of_files.txt | xargs cksum
ist wahrscheinlich nicht das, was Sie wollen. Ihr Beispiel wird funktionieren, aber im Allgemeinen benötigen Sie zusätzliche Anführungszeichen und/oder Backslashs in der Datei; xor benötigen Sie, xargs -d '\n'
wobei where -d
eine nicht portable Option von GNU ist xargs
. Meine Annahme war „Pfade in der Datei werden durch Zeilenumbrüche beendet und so bereitgestellt, wie sie sind“. Mit dieser Annahme parallel
funktioniert GNU sofort (d. h. ohne zusätzliche Optionen), xargs nicht. Mit GNU xargs
können Sie Folgendes tun:
shuf -n 3 list_of_files.txt | xargs -d '\n' cksum
Wenn Sie GNU verwenden können xargs
(um die Situation zu retten -d '\n'
), dann können Sie wahrscheinlich auch GNU verwenden parallel
. Wenn Sie -j 1
bei der Verwendung von GNU vergessen parallel
, kann die Leistung des Befehls schlechter sein, aber er funktioniert trotzdem. Wenn Sie -d '\n'
bei der Verwendung von GNU vergessen xargs
und die Pfadnamen unverändert bereitgestellt werden, handelt es sich um einen Fehler. Aus diesem Grund empfehle ich parallel
zuerst GNU.
GNU parallel kann nullterminierte Strings verarbeiten (die Option ist -0
), ebenso GNU xargs
( -0
statt -d '\n'
) und GNU shuf
( mit -z
). Ihre Eingabedatei verwendet Zeilen, die durch Zeilenumbrüche terminiert sind, aber wenn Sie jemals mit Pfadnamen arbeiten müssen, die (möglicherweise) Zeilenumbruchzeichen enthalten, sollten Sie den Terminator in der Datei ändern und die entsprechenden Optionen hinzufügen.