Aufrufen mehrerer Bash-Skripte und parallele Ausführung, nicht nacheinander

19

Nehmen wir an, dass ich drei (oder mehr) Bash - Skripte: script1.sh, script2.sh, und script3.sh. Ich möchte alle drei Skripte aufrufen und parallel ausführen . Eine Möglichkeit, dies zu tun, besteht darin, einfach die folgenden Befehle auszuführen:

nohup bash script1.sh &
nohup bash script2.sh &
nohup bash script3.sh &

(Im Allgemeinen kann es mehrere Stunden oder Tage dauern, bis die Skripts fertig sind. Daher möchte ich sie verwenden, nohupdamit sie auch dann ausgeführt werden, wenn meine Konsole geschlossen wird.)

Aber ist es eine Möglichkeit , diese drei Befehle in auszuführen parallel mit einem einzigen Anruf?

Ich dachte so etwas wie

nohup bash script{1..3}.sh &

aber dies scheint auszuführen script1.sh, script2.shund script3.shin der Reihenfolge, nicht parallel.

Andrew
quelle
2
Was bedeutet "Einzelruf"?
JW013
1
Was ist der Anwendungsfall? Haben Sie eine Million Skripte, um zu beginnen?
l0b0
@ jw013 Ich meine, so etwas wie ein einzelner kurzer Zeilenbefehl. Wenn ich 100 Skripte zum Starten habe, möchte ich in der Lage sein, etwas Kurzes (wie nohup bash script{1..100}.sh &oder for i in {1..100}; do nohup bash script{1..100} &; done) einzugeben, anstatt nohup bash script*.sh &100 verschiedene Male einzugeben .
Andrew
1
Falls die Skripte eine nützliche Ausgabe haben: Sie können sie screenauch in (oder tmux) starten , um das Konsolenproblem zu lösen, aber den Zugriff auf die Ausgabe (und Eingabe) zu behalten.
Hauke ​​Laging
1
Es gibt nichts, was Sie daran hindert, alle drei dieser Befehle in derselben Zeile einzugeben. nohup ... & nohup ... & nohup ... &. Wenn Sie stattdessen alle Skripte ausführen möchten, ohne jeden Skriptnamen einzeln einzugeben, wird dies in einer einfachen Schleife ausgeführt.
jw013

Antworten:

16
for((i=1;i<100;i++)); do nohup bash script${i}.sh & done
Hauke ​​Laging
quelle
2
Ihnen fehlt eine enge Klammer.
David Conrad
1
@HaukeLaging Was ist, wenn die Skriptnamen unterschiedlich sind?
Patrick
14

Ein besserer Weg wäre, GNU Parallel zu verwenden . GNU parallel ist einfach und damit können wir die Anzahl der Jobs steuern, die parallel ausgeführt werden sollen, und die Jobs besser steuern.

Wird im folgenden Befehl script{1..3}.sherweitert und als Argumente an bashparallel gesendet . Hier wird -j0angegeben, dass so viele Jobs wie möglich ausgeführt werden sollen. Standardmäßig wird parallelein Job für einen CPU-Kern ausgeführt.

$ parallel -j0 bash :::: <(ls script{1..3}.sh)

Und Sie können es auch mit versuchen

$ parallel -j0 bash ::: script{1..3}.sh

Wenn beim Ausführen der zweiten Methode eine Fehlermeldung angezeigt wird, bedeutet dies, dass die --tollefOption aktiviert ist /etc/parallel/configund gelöscht werden muss, und alles funktioniert.

Sie können die GNU ParallelsManpage hier lesen , um weitere Optionen zu erhalten.

Wenn Sie die Jobs von einem Remotecomputer ausführen, sollten Sie sie besser verwenden, screendamit die Sitzung nicht aufgrund von Netzwerkproblemen geschlossen wird. nohupnicht erforderlich ist, wie die jüngsten Versionen von bash wie kommt huponexitwie , offund dies wird mehr senden Eltern - Shell verhindern HUPSignal an seine Kinder während seiner Ausfahrt. Wenn es nicht deaktiviert ist, machen Sie es mit

$ shopt -u huponexit  
Kannan Mohan
quelle
Wenn Sie verwenden möchten, bashwie die Shell parallel -j0 bash :::: <(ls script{1..3}.sh)reduziert werden kann parallel -j0 bash :::: script{1..3}.sh, nein?
Iruvar
Nein, nein, wenn '::::' mit parallel verwendet wird, bedeutet dies, dass das Argument eine Datei ist, die auszuführende Befehle enthält und nicht den Befehl selbst. Hier verwenden wir die Prozessersetzung, um die Skriptnamen innerhalb eines Dateideskriptors umzuleiten.
Kannan Mohan
Ähm .. in diesem Fall warum nicht parallel -j0 bash ::: script{1..3}.sh?
Iruvar
Es ist bash ::: script{1..3}.sh wird weitergegeben parallel, nicht ::: script{1..3}.sh. So sollte dies zunächst erweitern parallel bash ::: script1.sh script2.sh script3.shdurch die Schale und dann parallelAnrufungen bash script1.sh, bash script2.sh, bash script3.sh. Ich habe es versucht
iruvar
1
Nein, ich bin nicht verwirrt. Ich behaupte nur, dass das OP-Problem besser gelöst werden kann parallel -j0 bash ::: script{1..3}.sh - dies ist besser als der ::::Ansatz, da keine Prozesssubstitution erforderlich ist. Auch das Parsen der ls-Ausgabe ist mit Fallstricken
behaftet
9

Wir können auch xargsmehrere Skripte gleichzeitig ausführen.

$ ls script{1..5}.sh|xargs -n 1 -P 0 bash

Hier wird jedes Skript einzeln als Argument an bash übergeben. -P 0gibt an, dass die Anzahl der parallelen Prozesse so groß wie möglich sein kann. Es ist auch sicherer, bash default zu verwenden job control feature (&).

Yaalie
quelle
5

Eine einzeilige Lösung:

$ nohup bash script1.sh & nohup bash script2.sh & nohup bash script3.sh &

Verwenden Sie weniger scherzhaft nur ein Wrapper-Skript:

$ cat script.sh
#!/usr/bin/env bash
script1.sh &
script2.sh &
script3.sh &
$ nohup script.sh &

Oder überfliegen Sie sie:

for script in dir/*.sh
do
    nohup bash "$script" &
done
l0b0
quelle
2

Wenn Sie sich das Tippen sparen möchten

eval "nohup bash "script{1..3}.sh" &"

Oder vielleicht auch nicht

iruvar
quelle
1

Kasse dieses Werkzeug: https://github.com/wagoodman/bashful

Sagen Sie, Sie haben mytasks.yamlmit

tasks:
    - name: A title for some tasks
      parallel-tasks:
        - cmd: ./script1.sh
        - cmd: ./script2.sh -x an-arg
        - cmd: ./script3.sh -y some-other-arg

Und du machst es so:

nohup bashful run mytasks.yaml

Ihre Skripte würden parallel mit einem vertikalen Fortschrittsbalken ausgeführt (+ eta, wenn Sie es zuvor ausgeführt haben und die Zeit deterministisch ist). Sie können festlegen, wie viele Aufgaben gleichzeitig ausgeführt werden sollen, wenn Sie mehr als die angegebenen 3 ausführen:

config:
    max-parallel-commands: 6
tasks:
    ...

Haftungsausschluss: Ich bin der Autor.

Wagoodman
quelle
0

Ich schlage ein viel einfacheres Dienstprogramm vor, das ich gerade geschrieben habe. Es heißt derzeit par, wird aber bald entweder in parl oder pll umbenannt, hat sich aber noch nicht entschieden.

https://github.com/k-bx/par

API ist so einfach wie:

par "script1.sh" "script2.sh" "script3.sh"
Kostiantyn Rybnikov
quelle