Appeler plusieurs scripts bash et les exécuter en parallèle, pas en séquence

19

Supposons que j'ai trois (ou plus) scripts bash: script1.sh, script2.shet script3.sh. Je voudrais appeler ces trois scripts et les exécuter en parallèle . Pour ce faire, vous pouvez simplement exécuter les commandes suivantes:

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

(En général, les scripts peuvent prendre plusieurs heures ou jours pour se terminer, je voudrais donc les utiliser nohuppour qu'ils continuent de fonctionner même si ma console se ferme.)

Mais, existe-t-il un moyen d'exécuter ces trois commandes en parallèle avec un seul appel?

Je pensais à quelque chose comme

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

mais cela semble s'exécuter script1.sh, script2.shet script3.shen séquence, pas en parallèle.

Andrew
la source
2
Que signifie «appel unique»?
jw013
1
Quel est le cas d'utilisation? Avez-vous un million de scripts à démarrer?
l0b0
@ jw013 Je veux dire, quelque chose comme une seule commande de ligne courte. Si j'ai 100 scripts à démarrer, j'aimerais pouvoir taper quelque chose de court (comme nohup bash script{1..100}.sh &ou for i in {1..100}; do nohup bash script{1..100} &; done), plutôt que de taper nohup bash script*.sh &100 fois différents.
Andrew
1
Dans le cas où les scripts ont une sortie utile: vous pouvez également les démarrer à l'intérieur screen(ou tmux), afin de résoudre le problème de la console, mais garder l'accès à la sortie (et à l'entrée).
Hauke ​​Laging
1
Rien ne vous empêche de taper ces 3 commandes sur la même ligne. nohup ... & nohup ... & nohup ... &. Si vous voulez plutôt exécuter tous les scripts sans taper chaque nom de script individuellement, une simple boucle le fera.
jw013

Réponses:

16
for((i=1;i<100;i++)); do nohup bash script${i}.sh & done
Hauke ​​Laging
la source
2
Vous manquez une parenthèse étroite.
David Conrad
1
@HaukeLaging Et si les noms de script sont différents?
Patrick
14

Une meilleure façon serait d'utiliser GNU Parallel . GNU parallèle est simple et avec lui, nous pouvons contrôler le nombre de travaux à exécuter en parallèle avec plus de contrôle sur les travaux.

Dans la commande ci-dessous, script{1..3}.shest développé et envoyé en tant qu'arguments bashen parallèle. Ici -j0indique que le plus de travaux doivent être exécutés que possible. Par défaut, parallelexécute un travail pour un cœur de processeur.

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

Et vous pouvez également essayer d'utiliser

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

Lors de l'exécution de la deuxième méthode si vous obtenez un message d'erreur, cela signifie que l' --tollefoption est définie /etc/parallel/configet qu'elle doit être supprimée et tout fonctionnera correctement.

Vous pouvez lire la GNU Parallelspage de manuel ici pour des options plus riches.

Et dans le cas où vous exécutez les travaux à partir d'une machine distante, mieux vaut l'utiliser screenafin que la session ne soit pas fermée en raison de problèmes de réseau. nohupn'est pas nécessaire, car les versions récentes de bash sont fournies avec huponexitas offet cela empêchera le shell parent d'envoyer un HUPsignal à ses enfants lors de sa sortie. Dans le cas où ce n'est pas mal réglé, faites-le avec

$ shopt -u huponexit  
Kannan Mohan
la source
Si vous allez utiliser bashcar le shell parallel -j0 bash :::: <(ls script{1..3}.sh)peut être réduit à parallel -j0 bash :::: script{1..3}.sh, non?
iruvar
Non, ce n'est pas le cas, lorsque '::::' est utilisé avec parallèle, cela signifie que l'argument est un fichier qui contient des commandes à exécuter et non la commande elle-même. Ici, nous utilisons la substitution de processus pour rediriger les noms de script dans un descripteur de fichiers.
Kannan Mohan
Euh .. dans ce cas, pourquoi pas parallel -j0 bash ::: script{1..3}.sh?
iruvar
Il bash ::: script{1..3}.shest transmis à parallel, non ::: script{1..3}.sh. Donc , cela devrait d' abord étendre à parallel bash ::: script1.sh script2.sh script3.shpar la coquille, puis parallelinvocations bash script1.sh, bash script2.sh, bash script3.sh. Je l'ai essayé
iruvar
1
Non, je ne suis pas confus, tout ce que je dis, c'est que le problème de l'OP est mieux résolu parallel -j0 bash ::: script{1..3}.sh- c'est mieux que l' ::::approche car cela évite le besoin de substitution de processus. L' analyse de la sortie ls est également
semée
9

Nous pouvons également utiliser xargspour exécuter plusieurs scripts en parallèle.

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

ici, chaque script est passé à bash comme argument séparément. -P 0indique que le nombre de processus parallèles peut être autant que possible. Il est également plus sûr d'utiliser bash par défaut job control feature (&).

Yaalie
la source
5

Une seule ligne solution:

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

Moins facétieusement, utilisez simplement un script wrapper:

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

Ou bouclez-les:

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

Si vous cherchez à vous épargner quelques efforts de frappe

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

Ou à y réfléchir, peut-être pas

iruvar
la source
1

Découvrez cet outil: https://github.com/wagoodman/bashful

Dis que tu as mytasks.yamlavec

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

Et vous le faites comme ça:

nohup bashful run mytasks.yaml

Vos scripts seraient exécutés en parallèle avec une barre de progression verticale (+ eta si vous l'avez déjà exécuté et que l'heure est déterministe). Vous pouvez modifier le nombre de tâches que vous souhaitez exécuter en parallèle si vous commencez à exécuter plus que les 3 données ici:

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

Avertissement: je suis l'auteur.

wagoodman
la source
0

Je propose un utilitaire beaucoup plus simple que je viens d'écrire. Il est actuellement appelé par, mais sera renommé bientôt en parl ou en pll, pas encore décidé.

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

L'API est aussi simple que:

par "script1.sh" "script2.sh" "script3.sh"
Kostiantyn Rybnikov
la source