web-dev-qa-db-fra.com

Incrémenter une variable dans une boucle de Bash

J'essaie d'écrire un petit script qui comptera les entrées dans un fichier journal et j'incrémente une variable (USCOUNTER) que j'essaie d'utiliser une fois la boucle terminée.

Mais à ce moment, USCOUNTER semble être 0 au lieu de la valeur réelle. Une idée de ce que je fais mal? Merci!

FILE=$1

tail -n10 mylog > $FILE

USCOUNTER=0

cat $FILE | while read line; do
  country=$(echo "$line" | cut -d' ' -f1)
  if [ "US" = "$country" ]; then
        USCOUNTER=`expr $USCOUNTER + 1`
        echo "US counter $USCOUNTER"
  fi
done
echo "final $USCOUNTER"

Il produit:

US counter 1
US counter 2
US counter 3
..
final 0
40
maephisto

Vous utilisez USCOUNTER dans un sous-shell, c'est pourquoi la variable ne s'affiche pas dans le shell principal.

Au lieu de cat FILE | while ..., Faites simplement un while ... done < $FILE. De cette façon, vous évitez le problème commun de je définis des variables dans une boucle qui est dans un pipeline. Pourquoi elles disparaissent après la fin de la boucle? Pourquoi ne puis-je pas canaliser les données à lire? :

while read country _; do
  if [ "US" = "$country" ]; then
        USCOUNTER=$(expr $USCOUNTER + 1)
        echo "US counter $USCOUNTER"
  fi
done < "$FILE"

Note j'ai aussi remplacé l'expression `` avec un $ ().

J'ai également remplacé while read line; do country=$(echo "$line" | cut -d' ' -f1) par while read country _. Cela vous permet de dire while read var1 var2 ... varNvar1 Contient le premier mot de la ligne, $var2 Et ainsi de suite, jusqu'à ce que $varN Contienne le contenu restant.

43
fedorqui
while read -r country _; do
  if [[ $country = 'US' ]]; then
    ((USCOUNTER++))
    echo "US counter $USCOUNTER"
  fi
done < "$FILE"
23

minimaliste

counter=0
((counter++))
echo $counter
14
geekzspot

Vous obtenez final 0 parce que votre while loop est en cours d'exécution dans un sous-processus (Shell) et toutes les modifications apportées ne sont pas reflétées dans le Shell (parent) actuel.

script correct:

while read -r country _; do
  if [ "US" = "$country" ]; then
        ((USCOUNTER++))
        echo "US counter $USCOUNTER"
  fi
done < "$FILE"
13
anubhava

J'ai eu la même variable $ count dans une boucle while en perdant le problème.

La réponse de @ fedorqui (et quelques autres) sont des réponses précises à la question: le sous-shell est bien le problème.

Mais cela m’amène à un autre problème: je ne transmettais pas le contenu d’un fichier ... mais la sortie d’une série de tuyaux et de greps ...

mon exemple de code erroné:

count=0
cat /etc/hosts | head | while read line; do
  ((count++))
  echo $count $line
done
echo $count

et ma solution grâce à l'aide de ce fil et le substitution de processus :

count=0
while IFS= read -r line; do
  ((count++))
  echo "$count $line"
done < <(cat /etc/hosts | head)
echo "$count"
6
jobwat
USCOUNTER=$(grep -c "^US " "$FILE")
2
Walter A

En utilisant la commande 1 ligne suivante pour changer le nom de nombreux fichiers sous Linux en utilisant la spécificité de phrase:

find -type f -name '*.jpg' | rename 's/holiday/honeymoon/'

Pour tous les fichiers avec l'extension ".jpg", s'ils contiennent la chaîne "vacances", remplacez-la par "lune de miel". Par exemple, cette commande renommerait le fichier "ourholiday001.jpg" en "ourhoneymoon001.jpg".

Cet exemple montre également comment utiliser la commande find pour envoyer une liste de fichiers (-type f) avec l'extension .jpg (-name '* .jpg') à renommer via un tuyau (|). renommer lit ensuite sa liste de fichiers à partir de l’entrée standard.

0
thanh

Incrémenter une variable peut être fait comme ça:

  _my_counter=$[$_my_counter + 1]

Compter le nombre d'occurrences d'un motif dans une colonne peut être fait avec grep

 grep -cE "^([^ ]* ){2}US"

-c compter

([^ ]* ) Pour détecter une colonne

{2} le numéro de colonne

US votre modèle

0
trax