Wywoływanie wielu skryptów bash i uruchamianie ich równolegle, a nie po kolei

19

Załóżmy, że mam trzy (lub więcej) skrypty bash: script1.sh, script2.sh, i script3.sh. Chciałbym wywołać wszystkie trzy skrypty i uruchomić je równolegle . Jednym ze sposobów jest wykonanie następujących poleceń:

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

(Ogólnie rzecz biorąc, skrypty mogą potrwać kilka godzin lub dni, więc chciałbym ich użyć nohup, aby kontynuowały działanie nawet po zamknięciu konsoli).

Ale czy jest jakiś sposób na wykonanie tych trzech poleceń równolegle za pomocą jednego wywołania?

Myślałem o czymś takim

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

ale wydaje się to wykonać script1.sh, script2.shi script3.shkolejno, a nie równolegle.

Andrzej
źródło
2
Co oznacza „pojedyncze połączenie”?
jw013,
1
Jaki jest przypadek użycia? Czy masz milion skryptów do uruchomienia?
l0b0,
@ jw013 Mam na myśli coś takiego jak polecenie z krótkiej linii. Jeśli mam 100 skryptów do uruchomienia, chciałbym móc napisać coś krótkiego (jak nohup bash script{1..100}.sh &lub for i in {1..100}; do nohup bash script{1..100} &; done), zamiast pisać nohup bash script*.sh &100 razy.
Andrew
1
W przypadku, gdy skrypty mają przydatne dane wyjściowe: Możesz je również uruchomić w screen(lub tmux), aby rozwiązać problem z konsolą, ale zachować dostęp do danych wyjściowych (i danych wejściowych).
Hauke ​​Laging
1
Nic nie stoi na przeszkodzie, aby wpisać wszystkie 3 polecenia w tym samym wierszu. nohup ... & nohup ... & nohup ... &. Jeśli masz na myśli, że chcesz uruchomić wszystkie skrypty bez wpisywania nazwy każdego skryptu osobno, zrobi to prosta pętla.
jw013,

Odpowiedzi:

16
for((i=1;i<100;i++)); do nohup bash script${i}.sh & done
Hauke ​​Laging
źródło
2
Brakuje ciasnego nawiasu.
David Conrad,
1
@HaukeLaging Co zrobić, jeśli nazwy skryptów są różne?
Patrick
14

Lepszym sposobem byłoby użycie GNU Parallel . GNU równoległy jest prosty i dzięki nim możemy kontrolować liczbę zadań do uruchomienia równoległego z większą kontrolą nad zadaniami.

W poniższym poleceniu script{1..3}.shrozwija się i są wysyłane jako argumenty bashrównolegle do. Tutaj -j0wskazuje jak wiele miejsc pracy powinny być prowadzone, jak to możliwe. Domyślnie paralleluruchamia jedno zadanie dla jednego rdzenia procesora.

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

Możesz także spróbować użyć

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

Podczas wykonywania drugiej metody, jeśli pojawi się komunikat o błędzie, oznacza to, że --tollefopcja jest włączona /etc/parallel/configi że należy ją usunąć, a wszystko będzie działać poprawnie.

Możesz przeczytać GNU Parallelsstronę man tutaj, aby uzyskać bogatsze opcje.

A jeśli screenwykonujesz zadania ze zdalnego komputera, lepiej użyj, aby sesja nie została zamknięta z powodu problemów z siecią. nohupnie jest konieczne, ponieważ najnowsze wersje bash są dostarczane jako huponexitas, offco zapobiegnie wysyłaniu przez powłokę nadrzędną HUPsygnału do jej dzieci podczas wychodzenia. W przypadku, gdy nie jest rozbrojony, zrób to

$ shopt -u huponexit  
Kannan Mohan
źródło
Jeśli zamierzasz użyć, bashponieważ parallel -j0 bash :::: <(ls script{1..3}.sh)można zmniejszyć powłokę parallel -j0 bash :::: script{1..3}.sh, nie?
iruvar
Nie, nie jest, gdy „::::” jest używane równolegle, oznacza to, że argument jest plikiem zawierającym polecenia do wykonania, a nie samym poleceniem. W tym przypadku używamy podstawiania procesów do przekierowywania nazw skryptów w deskryptorze plików.
Kannan Mohan
Eee… w takim razie dlaczego nie parallel -j0 bash ::: script{1..3}.sh?
iruvar
To bash ::: script{1..3}.shjest przekazywane parallel, nie ::: script{1..3}.sh. Więc powinno to pierwsze rozszerzenie do parallel bash ::: script1.sh script2.sh script3.shprzez powłokę i następnie parallelwywołań bash script1.sh, bash script2.sh, bash script3.sh. Próbowałem
iruvar,
1
Nie, nie jestem zdezorientowany, stwierdzam tylko, że problem PO jest lepiej rozwiązany parallel -j0 bash ::: script{1..3}.sh- jest to lepsze niż ::::podejście, ponieważ pozwala uniknąć konieczności zastępowania procesów. Również parsowania wyjście ls jeździł z pułapek
Iruvar
9

Możemy również użyć xargsdo uruchomienia wielu skryptów równolegle.

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

tutaj każdy skrypt jest osobno przekazywany do bash jako argument. -P 0wskazuje, że liczba równoległych procesów może być jak największa. Bezpieczniej jest też korzystać z domyślnej wersji bash job control feature (&).

Yaalie
źródło
5

Pojedyncza linia rozwiązanie:

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

Mniej żartobliwie, po prostu użyj skryptu opakowania:

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

Lub zapętl się nad nimi:

for script in dir/*.sh
do
    nohup bash "$script" &
done
l0b0
źródło
2

Jeśli chcesz zaoszczędzić trochę czasu na pisanie

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

Albo po namyśle, może nie

iruvar
źródło
1

Sprawdź to narzędzie: https://github.com/wagoodman/bashful

Załóżmy, że masz mytasks.yamlz

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

I działasz tak:

nohup bashful run mytasks.yaml

Twoje skrypty byłyby uruchamiane równolegle z pionowym paskiem postępu (+ eta, jeśli uruchomiłeś go wcześniej, a czas jest deterministyczny). Możesz dostosować liczbę zadań, które chcesz uruchomić równolegle, jeśli zaczniesz uruchamiać więcej niż tylko podane 3 tutaj:

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

Oświadczenie: Jestem autorem.

wagoodman
źródło
0

Sugeruję znacznie prostsze narzędzie, które właśnie napisałem. Obecnie nazywa się par, ale wkrótce zostanie zmieniona na parl lub pll, jeszcze nie zdecydowałem.

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

Interfejs API jest tak prosty, jak:

par "script1.sh" "script2.sh" "script3.sh"
Kostiantyn Rybnikov
źródło