J'ai le script simple suivant dans lequel j'exécute une boucle et je souhaite maintenir un fichier COUNTER
. Je n'arrive pas à comprendre pourquoi le compteur ne se met pas à jour. Est-ce dû à un sous-shell 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
Réponses:
Premièrement, vous n'augmentez pas le compteur. Changer
COUNTER=$((COUNTER))
enCOUNTER=$((COUNTER + 1))
ouCOUNTER=$[COUNTER + 1]
va l'augmenter.Deuxièmement, il est plus difficile de rétropropager des variables de sous-shell à 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:
la source
$[...]
est obsolète? Existe-t-il une solution alternative?$[...]
a été utilisé parbash
avant a$((...))
été adopté par le shell POSIX. Je ne suis pas sûr qu'il ait jamais été formellement obsolète, mais je ne trouve aucune mention à ce sujet dans labash
page de manuel, et il semble être pris en charge uniquement pour la compatibilité ascendante....
BASH TESTÉ: Centos, SuSE, RH
la source
$[ ]
syntaxe est obsolète. stackoverflow.com/questions/10515964/…est une construction assez maladroite dans la programmation moderne.
semble plus «moderne». Vous pouvez aussi utiliser
si vous pensez que cela améliore la lisibilité. Parfois, Bash donne trop de façons de faire les choses - la philosophie Perl je suppose - alors que Python "il n'y a qu'une seule bonne façon de le faire" pourrait être plus approprié. C'est une déclaration discutable s'il y en a jamais eu! Quoi qu'il en soit, je suggérerais que le but (dans ce cas) n'est pas seulement d'incrémenter une variable mais (règle générale) d'écrire également du code que quelqu'un d'autre peut comprendre et prendre en charge. La conformité contribue grandement à y parvenir.
HTH
la source
Essayez d'utiliser
au lieu de
la source
let "COUNTER++"
(( COUNTER++ ))
(pas de signe dollar)(( COUNTER++ ))
mais lorsque je suis passé,COUNTER=$((COUNTER + 1))
cela a fonctionné.GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Je pense que cet appel awk unique est équivalent à votre
grep|grep|awk|awk
pipeline: 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, donc toute modification apportée à la variable disparaît lorsque le sous-shell se termine. Vous devez accéder à la valeur de COUNTER dans ce même sous-shell. Ou suivez les conseils de @ DennisWilliamson, utilisez une substitution de processus et évitez complètement le sous-shell.
la source
la source
Au lieu d'utiliser un fichier temporaire, vous pouvez éviter de créer un sous-shell autour de la
while
boucle en utilisant la substitution de processus.Au fait, vous devriez pouvoir transformer tout cela
grep, grep, awk, awk, awk
en un seulawk
.À partir de Bash 4.2, il existe une
lastpipe
option quila source
lastpipe
. Au fait, vous devriez probablement utiliser"${PIPESTATUS[@]}"
(at au lieu de l'astérisque).minimaliste
la source
C'est tout ce que vous devez faire:
Voici un extrait de Learning the bash Shell , 3e édition, pp.147, 148:
..........................
Voir http://www.safaribooksonline.com/a/learning-the-bash/7572399/
la source
if
déclaration:if [[ $((needsComma++)) -gt 0 ]]; then printf ',\n'; fi
vrai ou faux, c'est la seule version qui a fonctionné de manière fiable.i=1; while true; do echo $((i++)); sleep .1; done
if (( needsComma++ > 0 )); then
ouif (( needsComma++ )); then
Ceci est un exemple simple
la source
Il semble que vous n'ayez pas mis à jour
counter
le script, utilisezcounter++
la source
Il y avait deux conditions qui ont fait échouer l'expression
((var++))
pour moi:Si je mets bash en mode strict (
set -euo pipefail
) et si je commence mon incrément à zéro (0).Commencer à un (1) est très bien, mais zéro fait que l'incrément renvoie "1" lors de l'évaluation de "++" qui est un échec de code de retour différent de zéro en mode strict.
Je peux utiliser
((var+=1))
ouvar=$((var+1))
échapper à ce comportementla source
Le script source a un problème avec le sous-shell. Premier exemple, vous n'avez probablement pas besoin de sous-shell. Mais nous ne savons pas ce qui est caché sous "Encore plus d'action". La réponse la plus populaire a un bogue caché, qui augmentera les E / S, et ne fonctionnera pas avec le sous-shell, car il restaure le routeur à l'intérieur de la boucle.
N'ajoutez pas le signe '\', cela informera l'interpréteur bash de la continuation de la ligne. J'espère que cela vous aidera, vous ou n'importe qui. Mais à mon avis, ce script devrait être entièrement converti en script AWK, ou bien réécrit en python à l'aide de regexp ou de perl, mais la popularité de perl au fil des ans est dégradée. Mieux vaut le faire avec python.
Version corrigée sans sous-shell:
Version avec sous-shell si c'est vraiment nécessaire
la source