Führen Sie Bash-Skripte gleichzeitig im Ordner aus

10

Nehmen wir an, ich habe fünf Bash ( .sh) - Skripte in einem Ordner ( my_folder), die wie folgt benannt sind:

script_1.sh
script_2.sh
script_3.sh
script_4.sh
script_5.sh

Wie kann ich ein sechstes Bash-Skript oder nur einen Einzeiler schreiben, der alle diese Skripte zusammen ausführt?

Ich brauche die fünf Skripte, um alle gleichzeitig und nicht nacheinander auszuführen.

aaaaa
quelle

Antworten:

12

GNU parallelist perfekt für solche Dinge. Installieren mit sudo apt install parallelund dann:

parallel -j0 ::: my_folder/*sh

Das -jsteuert, wie viele Prozesse nicht parallel ausgeführt werden, und -j0bedeutet "alle". Setzen Sie es auf einen anderen Wert (z. B. -j20), um die Skripte stattdessen stapelweise auszuführen.

Terdon
quelle
1
Hinweis: Es gibt auch den parallelBefehl aus dem moreutilsPaket. Die Beispielverwendung: parallel -j 20 -- my_folder/*.sh(Im Gegensatz zu GNU parallelwerden -j0die Skripte einzeln ausgeführt.)
JFS
1
@jfs guter Punkt. Beachten Sie jedoch, dass sudo apt install paralleldie Datei /usr/bin/paralleldurch die von GNU parallel ersetzt wird. Solange Sie es installieren, sollte es, wie meine Antwort andeutet, wie erwartet funktionieren.
Terdon
Ja, ich hatte es auf die harte Tour herausgefunden, als ich erfolglose parallelBefehle aus dem Handbuch versuchte, während ich meine Antwort schrieb, um GNU parallel vorzuschlagen.
JFS
9

Um alle Skripte gleichzeitig (parallel) auszuführen, verwenden Sie:

script_1.sh &
script_2.sh &
script_3.sh &
script_4.sh &
script_5.sh &

Um das eine nach dem anderen (nacheinander) auszuführen, verwenden Sie:

script_1.sh &&
script_2.sh &&
script_3.sh &&
script_4.sh &&
script_5.sh

Verbesserung für Kommentare

Wenn Sie 200 Skripte haben, die Sie gleichzeitig ausführen möchten (was die Maschine übrigens blockieren könnte), verwenden Sie dieses Skript:

#!/bin/bash
for Script in my_folder/*.sh ; do
    echo bash "$Script" &
done

Setzen Sie die Skriptattribute mit dem folgenden Befehl auf ausführbar:

chmod a+x /path/to/script.sh

Wenn Sie das Skript zum ersten Mal ausführen, werden nur die Namen der 200 Skripte wiedergegeben, die ausgeführt werden. Wenn Sie zufrieden sind, werden die richtigen Namen ausgewählt. Bearbeiten Sie das Skript und ändern Sie diese Zeile:

    echo bash "$Script" &

zu:

    bash "$Script" &

Es gibt drei Möglichkeiten, wie Sie ein Bash-Skript von einem anderen aufrufen können, wie hier beantwortet:

  1. Machen Sie das andere Skript ausführbar, fügen Sie die #!/bin/bashZeile oben und den Pfad, in dem sich die Datei befindet, zur $PATHUmgebungsvariablen hinzu. Dann können Sie es als normalen Befehl aufrufen;

  2. Oder rufen Sie es mit dem Quellbefehl (Alias ​​ist.) So auf : source /path/to/script;

  3. Oder verwenden Sie den Befehl bash, um es auszuführen : /bin/bash /path/to/script;

Im Fall von OP enthielten eines oder mehrere der 200 Skripte nicht die #!/bin/basherste Zeile von shebang in der Datei. Als solche musste Option 3. verwendet werden.


200 Skripte werden gleichzeitig ausgeführt

Es wurde ein Kommentar dazu abgegeben, ob sie "zur gleichen Zeit laufen". Auf einem typischen 8-CPU-System teilen sich 25 Skripte gleichzeitig eine CPU, es wird jedoch jeweils nur ein Skript ausgeführt, bis die Zeitscheibe (gemessen in Millisekunden) abgelaufen ist. Dann erhält der nächste Job seinen angemessenen Anteil an Millisekunden, dann der nächste Job usw. usw.

In losen Worten können wir sagen, dass 200 Jobs "gleichzeitig", aber nicht "gleichzeitig" auf 8 CPUs ausgeführt werden, was 25 Jobs pro CPU entspricht:

Thread States.png

Oben Bild und Kommentare unten vom Linux-Kernel-Scheduler

Zeitscheibe.png

WinEunuuchs2Unix
quelle
Danke. Die Sache ist, dass ich in meinem realen Fall mehr als 200 Skripte ausführen muss. Gibt es also eine Möglichkeit, alle mit einem einzigen Befehl auszuführen (dh ohne ihre Dateinamen zu schreiben)?
aaaaa
@aaaaa Ich habe die Antwort für 200 Skripte geändert.
WinEunuuchs2Unix
Vielen Dank. es funktioniert .. das einzige, was ich zu deiner letzten Zeile hinzufügen musste, war 'bash'. Andernfalls wird mir die Erlaubnis verweigert.
aaaaa
1
@aaaaa Ziehen Sie es tatsächlich vor, dass alle über 200 Skripte gleichzeitig ausgeführt werden, oder möchten Sie lieber eine kleinere Anzahl (z. B. 10) gleichzeitig ausführen, wobei die anderen in die Warteschlange gestellt werden, wenn eines oder mehrere von ihnen fertig sind und Die Anzahl der aktuell ausgeführten Skripte fällt unter diese Anzahl? (Wenn Sie an solchen Lösungen interessiert sind, schlage ich vor, Ihre Frage mit Informationen darüber zu bearbeiten, wie viele Skripte Sie haben, wie lange sie normalerweise ausgeführt werden, welche Art von Arbeit sie ausführen usw.)
Eliah Kagan
@aaaaa Danke für das Feedback. Ich habe die Antwort so aktualisiert, dass sie das bashPräfix zum Aufrufen des Skripts enthält.
WinEunuuchs2Unix
3

Es gibt ein Werkzeug dafür, lesen Sie man run-parts.

Zum Beispiel mache ich:

 run-parts ${visorhome}/pbackup.d/

in meinem Palm Pilot Backup-Skript. ${visorhome}/pbackup.d/::

01PopulateJpilot  02Extract_Pedometer  03URLs  04google  05Books  06Weight  07Sec  08Bkgm 50hardlinks
Walzer
quelle
1
@ eliah-kagan Das Ausführen von "mehr als 200 Skripten" "gleichzeitig" erscheint unklug. Es könnte eine gute Möglichkeit sein, ein System einem Stresstest zu unterziehen
Waltinator
Guter Punkt. Ich denke, Sie möchten vielleicht noch erwähnen, dass run-partsdie Skripte nacheinander und nicht alle auf einmal ausgeführt werden, wie es das OP verlangt hat. Sie haben jedoch Recht, dass das Ausführen von 200 Skripten auf einmal wahrscheinlich nicht die gleiche Leistung wie das Ausführen von 5 aufweist - und selbst wenn das gleichzeitige Ausführen aller Skripte keine Probleme verursacht, ist dies möglicherweise immer noch unnötig. Ich habe kommentiert , um dem OP vorzuschlagen, ihre diesbezüglichen Präferenzen zu klären.
Eliah Kagan
run-partsführt die Skripte nicht aus (sie haben einen Punkt im Namen:my_folder/*.sh
jfs
1
run-partshat aus irgendeinem seltsamen Grund sehr spezifische Anforderungen an den Dateinamen. Es werden keine Dateinamen mit Erweiterungen gestartet, daher befürchte ich, dass dies hier nicht funktioniert.
Terdon
1

So führen Sie alle *.shSkripte gleichzeitig im my_folderVerzeichnis aus xargs:

$ ls my_folder/*.sh | xargs -P0 -n1 bash

So begrenzen Sie die Anzahl gleichzeitig ausgeführter Skripte auf 10:

$ ls my_folder/*.sh | xargs -P10 -n1 bash
jfs
quelle
Es ist eine schlechte Praxis, die Ausgabe von lsin einem Skript zu verwenden. Verwenden findist viel sicherer. Es ist das allererste Element hier: mywiki.wooledge.org/BashPitfalls#for_f_in_.24.28ls_.2A.mp3.29
Joe
@ Joe im Allgemeinen ist es wahr. Ich sehe in diesem speziellen Fall keine Probleme.
JFS
Das liegt daran, dass Sie bereits davon wissen. Leute, die später hierher kommen, könnten es nicht.
Joe
@ Joe folge dem Dogma nicht blind. Denken Sie selbst, dass eine Option besser ist als eine andere, was in Ihrem Fall Kompromisse sind.
JFS
Es ist kein Dogma. Ich bin alergic zu denen. Aber ich habe gesehen, was ich ausstrahlen kann. Das Parsen von lesbaren Ausgaben ist nicht zuverlässig. Es gibt keinen Anreiz für Entwickler zu behalten
Joe