web-dev-qa-db-fra.com

Boucle Bash, imprimer l'itération actuelle?

Disons que vous avez une simple boucle

while read line
do
  printf "${line#*//}\n"
done < text.txt

Existe-t-il une manière élégante d’imprimer l’itération en cours avec la sortie? Quelque chose comme

 0 The 
 1 quick 
 2 brown 
 3 fox 

J'espère éviter de définir une variable et de l'incrémenter à chaque boucle.

18
Steven Penny

Pour ce faire, vous devez incrémenter un compteur à chaque itération (comme vous essayez d'éviter).

count=0
while read -r line; do
   printf '%d %s\n' "$count" "${line*//}"
   (( count++ ))
done < test.txt

EDIT: Après un peu plus de réflexion, vous pouvez le faire sans compteur si vous avez la version 4 ou plus de bash:

mapfile -t arr < test.txt
for i in "${!arr[@]}"; do
   printf '%d %s' "$i" "${arr[i]}"
done

Le fichier intégré de mapfile lit l'intégralité du contenu du fichier dans le tableau. Vous pouvez ensuite parcourir les index du tableau, qui seront les numéros de ligne et accéder à cet élément. 

23
jordanm

Vous ne le voyez pas souvent, mais vous pouvez avoir plusieurs commandes dans la clause de condition d'une boucle while. Ce qui suit nécessite toujours une variable de compteur explicite, mais la disposition peut être plus appropriée ou plus attrayante pour certaines utilisations.

while ((i++)); read -r line
do
    echo "$i $line"
done < inputfile

La condition while est satisfaite quelle que soit la dernière commande renvoyée (read dans ce cas).

Certaines personnes préfèrent inclure la variable do sur la même ligne. Voici à quoi cela ressemblerait:

while ((i++)); read -r line; do
    echo "$i $line"
done < inputfile
13
n=0
cat test.txt | while read line; do
  printf "%7s %s\n" "$n" "${line#*//}"
  n=$((n+1))
done

Cela fonctionnera bien sûr dans Bourne Shell.

Si vous voulez vraiment éviter d'incrémenter une variable, vous pouvez diriger la sortie via grep ou awk:

cat test.txt | while read line; do
  printf " %s\n" "${line#*//}"
done | grep -n .

ou

awk '{sub(/.*\/\//, ""); print NR,$0}' test.txt
1
Graham

Vous pouvez utiliser une plage à parcourir, ce peut être un tableau, une chaîne, une ligne d'entrée ou une liste.

Dans cet exemple, j'utilise une liste de nombres [0..10] est également utilisée avec un incrément de 2.

#!/bin/bash
for i in {0..10..2}; do 
   echo " $i times"
done

La sortie est:

 0 times
 2 times
 4 times
 6 times
 8 times
 10 times

Pour imprimer l'index quelle que soit la plage de la boucle, vous devez utiliser une variable "COUNTER = 0" et l'augmenter à chaque itération "COUNTER + 1".

ma solution imprime chaque itération, le FOR traverse une ligne d'entrée et incrémente d'une unité à chaque itération, affiche également chacun des mots de la ligne d'entrée: 

#!/bin/bash 

COUNTER=0
line="this is a sample input line"

for Word in $line; do        
    echo "This i a Word number $COUNTER: $Word"
    COUNTER=$((COUNTER+1))
done

La sortie est:

This i a Word number 0: this
This i a Word number 1: is
This i a Word number 2: a
This i a Word number 3: sample
This i a Word number 4: input
This i a Word number 5: line

pour en savoir plus sur les boucles: entrez la description du lien ici

pour tester vos scripts: entrez la description du lien ici

0
Sergio Perez

Mise à jour: Les autres réponses publiées ici sont meilleures, notamment celles de @Graham et @DennisWilliamson.

Quelque chose de très semblable devrait convenir à:

tr -s ' ' '\n' <test.txt | nl -ba

Vous pouvez ajouter un indicateur -v0 à la commande nl si vous souhaitez indexer à partir de 0.

0
thb