165 votes

L'incrément de compteur dans la boucle Bash ne fonctionne pas

J'ai le script simple suivant où je lance une boucle et que je veux maintenir un compteur. Je suis incapable de comprendre pourquoi le compteur ne se met pas à jour. Est-ce dû au sous-shell qui est créé? Comment puis-je potentiellement résoudre ce problème

 #!/bin/bash
WFY_PATH=/var/log/nginx
WFY_FILE=error.log
COUNTER=0
grep 'GET /log_' $WFY_PATH/$WFY_FILE | grep 'upstream timed out' | awk -F ', ' '{print $2,$4,$0}' | awk '{print "http://domain.com"$5"&ip="$2"&date="$7"&time="$8"&end=1"}' | awk -F '&end=1' '{print $1"&end=1"}' |
(
while read WFY_URL
do
    echo $WFY_URL #Some more action
    COUNTER=$((COUNTER+1))
done
)

echo $COUNTER # output = 0
 

Merci Sparad

184voto

bos Points 3373

Tout d'abord, vous n'augmentez pas le compteur. Changer COUNTER=$((COUNTER)) en COUNTER=$((COUNTER + 1)) ou COUNTER=$[COUNTER + 1] l'augmentera.

Deuxièmement, il est plus difficile de rétrodiffuser les variables de sous-shell vers l'appelé, comme vous le supposez. Les variables d'un sous-shell ne sont pas disponibles en dehors du sous-shell. Ce sont des variables locales au processus enfant.

Une façon de le résoudre consiste à utiliser un fichier temporaire pour stocker la valeur intermédiaire:

 TEMPFILE=/tmp/$$.tmp
echo 0 > $TEMPFILE

# Loop goes here
  # Fetch the value and increase it
  COUNTER=$[$(cat $TEMPFILE) + 1]

  # Store the new value
  echo $COUNTER > $TEMPFILE

# Loop done, script done, delete the file
unlink $TEMPFILE
 

110voto

Jay Stan Points 237
 COUNTER=1
while [ Your != "done" ]
do
     echo " $COUNTER "
     COUNTER=$[$COUNTER +1]
done
 

BASH TESTÉ: Centos, SuSE, RH

60voto

Bill Parker Points 1
COUNTER=$((COUNTER+1)) 

est assez maladroit de construire dans la programmation moderne.

(( COUNTER++ ))

l'air plus "moderne". Vous pouvez également utiliser

let COUNTER++

si vous pensez à ce qui améliore la lisibilité. Parfois, Bash donne beaucoup de façons de faire les choses - Perl philosophie je suppose, quand peut-être le Python "il n'y a qu'une seule bonne façon de le faire" serait plus appropriée. C'est discutable si jamais il y en avait un! De toute façon, je suggère de l'objectif (dans ce cas) n'est pas seulement pour incrémenter une variable, mais (règle générale) écrire le code que quelqu'un d'autre peut le comprendre et de soutien. Conformité va un long chemin pour atteindre cet.

HTH

12voto

mkp Points 642
count=0   
base=1
(( COUNT += base ))

12voto

glenn jackman Points 69748

Je pense que cet appel awk est équivalent à votre pipeline grep|grep|awk|awk : veuillez le tester. Votre dernière commande awk semble ne rien changer du tout.

Le problème avec COUNTER est que la boucle while s'exécute dans un sous-shell, ainsi toutes les modifications apportées à la variable disparaissent à la fermeture du sous-shell. Vous devez accéder à la valeur de COUNTER dans le même sous-shell. Ou bien suivez les conseils de @ DennisWilliamson, utilisez un processus de substitution et évitez complètement le sous-shell.

 awk '
  /GET \/log_/ && /upstream timed out/ {
    split($0, a, ", ")
    split(a[2] FS a[4] FS $0, b)
    print "http://example.com" b[5] "&ip=" b[2] "&date=" b[7] "&time=" b[8] "&end=1"
  }
' | {
    while read WFY_URL
    do
        echo $WFY_URL #Some more action
        (( COUNTER++ ))
    done
    echo $COUNTER
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X