J'ai le script simple suivant où je lance une boucle et que je veux maintenir un COUNTER
. 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
Tout d'abord, vous n'augmentez pas le compteur. Remplacer COUNTER=$((COUNTER))
par 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
COUNTER=1
while [ Your != "done" ]
do
echo " $COUNTER "
COUNTER=$[$COUNTER +1]
done
BASH TESTÉ: Centos, SuSE, RH
COUNTER=$((COUNTER+1))
est une construction assez maladroite dans la programmation moderne.
(( COUNTER++ ))
semble plus "moderne". Vous pouvez aussi utiliser
let COUNTER++
si vous pensez que cela améliore la lisibilité. Parfois, Bash donne trop de façons de faire les choses - je suppose que la philosophie Perl - peut-être que le Python "il n’ya qu’une bonne façon de le faire" pourrait être plus approprié. C'est une déclaration discutable s'il en est une! Quoi qu'il en soit, je dirais que l'objectif (dans ce cas) n'est pas simplement d'incrémenter une variable, mais (règle générale) d'écrire également du code que quelqu'un d'autre peut comprendre et supporter. La conformité contribue grandement à atteindre cet objectif.
HTH
count=0
base=1
(( count += base ))
Essayez d'utiliser
COUNTER=$((COUNTER+1))
au lieu de
COUNTER=$((COUNTER))
Je pense que cet appel awk est équivalent à votre pipeline grep|grep|awk|awk
: testez-le. 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, de sorte que toute modification apportée à la variable disparaît à la fermeture du sous-shell. Vous devez accéder à la valeur de COUNTER dans ce même sous-shell. Vous pouvez également suivre les conseils de @ DennisWilliamson, utiliser un processus de substitution et éviter 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
}
Au lieu d'utiliser un fichier temporaire, vous pouvez éviter de créer un sous-shell autour de la boucle while
en utilisant la substitution de processus.
while ...
do
...
done < <(grep ...)
Soit dit en passant, vous devriez être capable de transformer tout ce grep, grep, awk, awk, awk
en un seul awk
.
À partir de Bash 4.2, il existe une option lastpipe
qui
exécute la dernière commande d'un pipeline dans le contexte Shell actuel. L'option lastpipe n'a aucun effet si le contrôle du travail est activé.
bash -c 'echo foo | while read -r s; do c=3; done; echo "$c"'
bash -c 'shopt -s lastpipe; echo foo | while read -r s; do c=3; done; echo "$c"'
3
minimaliste
counter=0
((counter++))
echo $counter
C'est tout ce que vous devez faire:
$((COUNTER++))
Voici un extrait de Apprentissage du shell bash , 3e édition, p. 147, 148:
bash les expressions arithmétiques sont équivalentes à leurs équivalents dans les langages Java et C. [9] La priorité et l’associativité sont les mêmes que dans C. Le tableau 6-2 indique les opérateurs arithmétiques pris en charge. Bien que certains d’entre eux soient (ou contiennent) des caractères spéciaux, il n’est pas nécessaire de les échapper par une barre oblique inversée, car ils sont dans la syntaxe $ ((...)).
..........................
Les opérateurs ++ et - sont utiles lorsque vous souhaitez incrémenter ou décrémenter une valeur de un. [11] Ils fonctionnent de la même manière que dans Java et C, par exemple, value ++ incrémente la valeur de 1. Cela s'appelle post-incrémentation ; il existe également une valeur pré-incrémentée : ++ . La différence devient évidente avec un exemple:
$ i=0
$ echo $i
0
$ echo $((i++))
0
$ echo $i
1
$ echo $((++i))
2
$ echo $i
2
Voir http://www.safaribooksonline.com/a/learning-the-bash/7572399/
Il semble que vous n'ayez pas mis à jour le counter
est le script, utilisez counter++