Question

Dans cette réponse à un autre question , on m'a dit que

  

dans les scripts que vous n'avez pas le contrôle de l'emploi   (Et d'essayer de le mettre en marche est stupide)

Ceci est la première fois que je l'ai entendu, et je l'ai scrute la section bash.info sur le contrôle d'emploi (chapitre 7), trouver aucune mention de l'une de ces affirmations. [ Mise à jour:. La page de manuel est un peu mieux, de mentionner l'utilisation « typique », les paramètres par défaut, et le terminal E / S, mais aucune vraie raison pour laquelle le contrôle de l'emploi est particulièrement mal avisé pour les scripts]

Alors, pourquoi fonctionne-contrôle de l'emploi non basée sur un script, et ce qui en fait une mauvaise pratique (alias « stupide »)?

Modifier Le script en question commence un processus d'arrière-plan, commence un second processus d'arrière-plan, puis tente de mettre le premier processus de retour au premier plan afin qu'il ait la borne normale E / S (comme si exécuter directement), qui peuvent ensuite être redirigés à partir de l'extérieur du script . Ne peut pas faire cela à un processus d'arrière-plan.

Comme l'a noté la réponse acceptée à l'autre question, il existe d'autres scripts qui permettent de résoudre ce problème particulier sans chercher l'emploi contrôle. Bien. Et le script fustigé utilise un certain nombre d'emplois codés en dur - De toute évidence mauvaise. Mais je suis en train de comprendre si le contrôle de l'emploi est une approche fondamentalement vouée. Il semble encore peut-être peut travail ...

Était-ce utile?

La solution

Ce qu'il voulait dire est que contrôle des tâches est désactivé par défaut en mode non-interactif (par exemple dans un script.)

A partir de la page man bash:

JOB CONTROL
       Job  control refers to the ability to selectively stop (suspend)
       the execution of processes and continue (resume) their execution at a
       later point.
       A user typically employs this facility via an interactive interface
       supplied jointly by the system’s terminal driver and bash.

et

   set [--abefhkmnptuvxBCHP] [-o option] [arg ...]
      ...
      -m      Monitor mode.  Job control is enabled.  This option is on by
              default for interactive shells on systems that support it (see
              JOB CONTROL above).  Background processes run in a separate
              process group and a line containing their exit status  is
              printed  upon  their completion.

Quand il dit « est stupide », il voulait dire que non seulement:

  1. est le contrôle de l'emploi signifie la plupart du temps pour faciliter le contrôle interactif (alors qu'un script peut travailler directement avec les pid de), mais aussi
  2. Je cite sa réponse originale, ... repose sur le fait que vous ne commencez pas à d'autres emplois précédemment dans le script qui est une mauvaise prise en charge de faire . Ce qui est tout à fait correct.

UPDATE

En réponse à votre commentaire: oui, personne ne vous empêche d'utiliser le contrôle de l'emploi dans votre script bash - il n'y a aucun cas difficile pour désactiver force set -m (oui, le contrôle de l'emploi à partir du script fonctionnera si vous le souhaitez.) Rappelez-vous qu'en fin de compte, en particulier dans les scripts, il y a toujours plus d'une façon à la peau d'un chat, mais certains moyens sont plus mobiles, plus fiables, le rendre plus simple à traiter les cas d'erreur, analyser la sortie, etc.

Vous circonstances particulières ou non justifier d'une manière différente de ce que lhunath (et d'autres utilisateurs) jugent « bonnes pratiques ».

Autres conseils

Le contrôle des tâches avec bg et fg est utile que dans les shells interactifs. Mais & conjointement avec wait est utile dans les scripts aussi.

Sur les systèmes multiprocesseurs fraye emplois de fond peut grandement améliorer les performances du script, par exemple dans les scripts de construction où vous voulez commencer au moins un compilateur par CPU, ou traiter des images en utilisant des outils ImageMagick etc en parallèle.

L'exemple suivant va jusqu'à 8 gcc parallèle de compiler tous les fichiers source dans un tableau:

#!bash
...
for ((i = 0, end=${#sourcefiles[@]}; i < end;)); do
    for ((cpu_num = 0; cpu_num < 8; cpu_num++, i++)); do
        if ((i < end)); then gcc ${sourcefiles[$i]} & fi
    done
    wait
done

Il n'y a rien de « stupide » à ce sujet. Mais vous aurez besoin de la commande wait , qui attend tous les travaux d'arrière-plan avant la script continue. Le PID du dernier travail de fond est stocké dans la variable $!, vous pouvez également wait ${!}. A noter également la commande nice .

Parfois, un tel code est utile dans makefiles:

buildall:
    for cpp_file in *.cpp; do gcc -c $$cpp_file & done; wait

Cela donne un contrôle beaucoup plus fin que make -j.

Notez que & est une terminaison de ligne comme ; (écriture de command& pas de command&;).

Hope this helps.

Le contrôle des tâches est utile que lorsque vous utilisez un shell interactif, à savoir, vous savez que stdin et stdout sont reliés à un dispositif terminal (/ dev / pts / * sous Linux). Ensuite, il est logique d'avoir quelque chose au premier plan, quelque chose d'autre sur fond, etc.

Scripts, d'autre part, ne dispose pas d'une telle garantie. Les scripts peuvent être exécutable faits et exécutés sans aucun terminal connecté. Il n'a pas de sens d'avoir des processus de premier plan ou arrière-plan dans ce cas.

Vous pouvez cependant exécuter d'autres commandes non interactive sur l'arrière-plan (annexant « et » à la ligne de commande) et de capturer leurs PIDs avec $!. Ensuite, vous utilisez kill pour tuer ou les suspendre (simuler Ctrl-C ou Ctrl-Z sur le terminal, il était la coquille interactive). Vous pouvez également utiliser wait (au lieu de fg) à attendre que le processus d'arrière-plan pour terminer.

Il pourrait être utile pour activer le contrôle de l'emploi dans un script pour définir des pièges sur SIGCHLD. La section CONTRÔLE DE L'EMPLOI dans le manuel dit:

  

Le shell apprend immédiatement chaque fois qu'un travail change d'état. Normalement,   bash attend jusqu'à ce qu'il soit sur le point d'imprimer une invite avant de faire rapport   des changements dans l'état d'un emploi afin de ne pas interrompre toute autre sortie. Si   l'option -b de la commande est activée, builtin rapports bash   ces changements immédiatement. Tout piège sur SIGCHLD est exécuté pour chaque   enfant qui sort.

(l'accent est à moi)

Prenez le script suivant, par exemple:

dualbus@debian:~$ cat children.bash 
#!/bin/bash

set -m
count=0 limit=3
trap 'counter && { job & }' CHLD
job() {
  local amount=$((RANDOM % 8))
  echo "sleeping $amount seconds"
  sleep "$amount"
}
counter() {
  ((count++ < limit))
}
counter && { job & }
wait
dualbus@debian:~$ chmod +x children.bash 
dualbus@debian:~$ ./children.bash 
sleeping 6 seconds
sleeping 0 seconds
sleeping 7 seconds

Remarque: le piégeage CHLD semble être rompu au bash 4.3

Dans bash 4.3, vous pouvez utiliser pour obtenir la même chose « attendre -n », cependant:

dualbus@debian:~$ cat waitn.bash 
#!/home/dualbus/local/bin/bash

count=0 limit=3
trap 'kill "$pid"; exit' INT
job() {
  local amount=$((RANDOM % 8))
  echo "sleeping $amount seconds"
  sleep "$amount"
}
for ((i=0; i<limit; i++)); do
  ((i>0)) && wait -n; job & pid=$!
done
dualbus@debian:~$ chmod +x waitn.bash 
dualbus@debian:~$ ./waitn.bash 
sleeping 3 seconds
sleeping 0 seconds
sleeping 5 seconds

On pourrait dire qu'il ya d'autres façons de le faire dans un plus manière portable, qui est, sans attendre CHLD ou -n:

dualbus@debian:~$ cat portable.sh 
#!/bin/sh

count=0 limit=3
trap 'counter && { brand; job & }; wait' USR1
unset RANDOM; rseed=123459876$$
brand() {
  [ "$rseed" -eq 0 ] && rseed=123459876
  h=$((rseed / 127773))
  l=$((rseed % 127773))
  rseed=$((16807 * l - 2836 * h))
  RANDOM=$((rseed & 32767))
}
job() {
  amount=$((RANDOM % 8))
  echo "sleeping $amount seconds"
  sleep "$amount"
  kill -USR1 "$$"
}
counter() {
  [ "$count" -lt "$limit" ]; ret=$?
  count=$((count+1))
  return "$ret"
}
counter && { brand; job & }
wait
dualbus@debian:~$ chmod +x portable.sh 
dualbus@debian:~$ ./portable.sh 
sleeping 2 seconds
sleeping 5 seconds
sleeping 6 seconds

Donc, en conclusion, mis en -m est pas utile dans les scripts, depuis la seule caractéristique intéressante qu'il apporte à des scripts est de pouvoir travailler avec SIGCHLD. Et il y a d'autres façons de réaliser la même chose soit plus court (attendez -n) ou plus portable (envoi de signaux vous-même).

Bash prend en charge le contrôle de l'emploi, comme vous le dites. Dans l'écriture de script shell, il y a souvent une hypothèse que vous ne pouvez pas compter sur le fait que vous avez bash, mais que vous avez le Bourne shell la vanille (de sh), qui historiquement ne contrôlaient pas d'emploi.

Je suis pressé dur ces jours-ci d'imaginer un système dans lequel vous honnêtement limité à la vraie Bourne shell. La /bin/sh de la plupart des systèmes sera lié à bash. Pourtant, il est possible. Une chose que vous pouvez faire est au lieu de spécifier

#!/bin/sh

Vous pouvez faire:

#!/bin/bash

Ce, et la documentation, indiquerait clairement votre script a besoin bash.

Peut-être o / t mais je l'utilise assez souvent nohup quand ssh à un serveur sur un travail de longue durée afin que si je suis connecté le travail est terminé encore.

Je me demande si les gens confondent l'arrêt et à partir d'un shell interactif maître et les processus d'arrière-plan de la reproduction? La commande d'attente vous permet de frayer beaucoup de choses et que vous attendez tous pour terminer, et comme je l'ai dit que je l'utilise nohup tout le temps. Il est plus complexe que cela et très sous-utilisé - sh prend en charge ce mode aussi. Jetez un coup d'oeil au manuel.

Vous avez également

kill -STOP pid

Je fais assez souvent que si je veux suspendre le cours d'exécution sudo, comme dans:

kill -STOP $$

Mais malheur à vous si vous avez sauté à la coquille d'un éditeur -. Cela va rester assis là

j'ai tendance à utiliser mnémotechnique -KILL etc. parce qu'il ya un danger de taper

kill - 9 pid # note the space

et dans les vieux jours, vous pouvez parfois amener la machine vers le bas, car il serait mort d'initialisation!

emplois ne fonctionnent dans les scripts bash

Mais, vous ... besoin de regarder pour le personnel donné naissance à comme:

ls -1 /usr/share/doc/ | while read -r doc ; do ... done

emplois auront contexte différent de chaque côté du |

contourner cela peut être en utilisant pour au lieu de tout:

for `ls -1 /usr/share/doc` ; do ... done

doit démontrer comment utiliser des emplois dans un script ... avec la mention que ma note est commenté ... REAL (dunno pourquoi ce comportement)

    #!/bin/bash


for i in `seq 7` ; do ( sleep 100 ) &  done

jobs

while [ `jobs | wc -l` -ne 0 ] ; do

    for jobnr in `jobs | awk '{print $1}' | cut -d\[ -f2- |cut -d\] -f1` ; do
        kill %$jobnr
    done
    #this is REALLY ODD ... but while won't exit without this ... dunno why
    jobs >/dev/null 2>/dev/null
done

sleep 1
jobs
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top