script bash pour exécuter un nombre constant de tâches en arrière-plan

J’ai besoin d’un script bash pour exécuter des tâches en arrière-plan, trois tâches à la fois.

Je sais que je peux le faire de la manière suivante, et pour illustration, je suppose que le nombre d’emplois est de 6:

./j1 & ./j2 & ./j3 & wait ./j4 & ./j5 & ./j6 & wait 

Cependant, si j2 et j3, par exemple, mettent beaucoup plus de temps à exécuter ce programme, je ne pourrai que travailler en arrière-plan pendant une longue période.

L’alternative (qui est ce que je veux) est que chaque fois qu’un travail est terminé, bash doit commencer le travail suivant dans la queue afin de maintenir un taux de 3 travaux à un moment donné. Est-il possible d’écrire un script bash pour implémenter cette alternative, éventuellement en utilisant une boucle? S’il vous plaît noter que je dois exécuter beaucoup plus d’emplois, et je m’attends à ce que cette méthode alternative me fasse économiser beaucoup de temps.

Voici mon brouillon du script, que j’espère que vous pouvez m’aider à vérifier son exactitude et à l’améliorer, comme je suis nouveau dans la création de scripts en bash. Les idées de ce script sont sockets et modifiées à partir d’ ici , ici et ici ):

 for i in $(seq 6) do # wait here if the number of jobs is 3 (or more) while (( (( $(jobs -p | wc -l) )) >= 3 )) do sleep 5 # check again after 5 seconds done jobs -x ./j$i & done wait 

IMHO, je pense que ce script fait le comportement requirejs. Cependant, je dois savoir – de bash experts – si je fais quelque chose de mal ou s’il existe une meilleure façon de mettre en œuvre cette idée.

Merci beaucoup.

Avec GNU xargs:

 printf '%s\0' j{1..6} | xargs -0 -n1 -P3 sh -c './"$1"' _ 

Avec bash (4.x) intégré:

 max_jobs=3; cur_jobs=0 for ((i=0; i<6; i++)); do # If true, wait until the next background job finishes to continue. ((cur_jobs >= max_jobs)) && wait -n # Increment the current number of jobs running. ./j"$i" & ((++cur_jobs)) done wait 

Notez que l’approche reposant sur les commandes intégrées comporte quelques cas particuliers: si plusieurs tâches quittent le même serveur au même moment, une seule wait -n peut en récupérer plusieurs, consommant ainsi plusieurs emplacements. Si nous voulions être plus robustes, nous pourrions nous retrouver avec quelque chose comme ceci:

 max_jobs=3 declare -A cur_jobs=( ) # build an associative array w/ PIDs of jobs we started for ((i=0; i<6; i++)); do if (( ${#cur_jobs[@]} >= max_jobs )); then wait -n # wait for at least one job to exit # ...and then remove any jobs that aren't running from the table for pid in "${!cur_jobs[@]}"; do kill -0 "$pid" 2>/dev/null && unset cur_jobs[$pid] done fi ./j"$i" & cur_jobs[$!]=1 done wait 

… ce qui est évidemment beaucoup de travail, et a toujours une course mineure. Pensez à utiliser xargs -P place. 🙂

Utiliser GNU Parallel:

 parallel -j3 ::: ./j{1..6} 

Ou si votre shell ne fait pas .. expansion (par exemple csh):

 seq 6 | parallel -j3 ./j'{}' 

Si vous pensez que vous ne pouvez pas installer GNU Parallel, veuillez lire http://oletange.blogspot.dk/2013/04/why-not-install-gnu-parallel.html et laissez un commentaire expliquant pourquoi vous ne pouvez pas l’installer.

Peut-être que cela pourrait aider ..

Exemple d’utilisation : exécutez ‘sleep 20’ 30 fois, par exemple. Cela pourrait être n’importe quel travail ou un autre script. Notre logique de contrôle est de continuer à vérifier si “combien ont déjà tiré?” est inférieur ou égal à “processus maxi définis”, dans une boucle while. Sinon, allumez-en un et si oui, dormez 0,5 seconde.

Sortie de script: Dans le snip ci-dessous, on observe que nous avons maintenant 30 commandes ‘sleep 20’ exécutées en arrière-plan, car nous avons configuré max = 30.

 %_Host@User> ps -ef|grep 'sleep 20'|grep -v grep|wc -l 30 %_Host@User> 

Changer la valeur de no. des jobs à l’exécution : le script a un paramètre “max”, qui prend la valeur d’un fichier “max.txt” ( max=$(cat max.txt) ) et l’applique ensuite à chaque itération de la boucle while. Comme on le voit ci-dessous, nous l’avons changé à 45 et maintenant nous avons 45 commandes ‘sleep 20’ en arrière-plan. Vous pouvez mettre le script principal en arrière-plan et continuer à changer la valeur max dans ” max.txt ” pour contrôler.

 %_Host@User> cat > max.txt 45 ^C %_Host@User> ps -ef|grep 'sleep 20'|grep -v grep|wc -l 45 %_Host@User> 

Scénario:

 #!/bin/bash #---------------------------------------------------------------------# proc='sleep 20' # Your process or script or anything.. max=$(cat max.txt) # configure how many jobs do you want curr=0 #---------------------------------------------------------------------# while true do curr=$(ps -ef|grep "$proc"|grep -v grep|wc -l); max=$(cat max.txt) while [[ $curr -lt $max ]] do ${proc} & # Sending process to background. max=$(cat max.txt) # After sending one job, again calculate max and curr curr=$(ps -ef|grep "$proc"|grep -v grep|wc -l) done sleep .5 # sleep .5 seconds if reached max jobs. done #---------------------------------------------------------------------# 

Dites-nous si c’était utile.