Loop gennem linjerne i en fil: Bash For Loop Forklaret
Jeg ønsker at loop gennem linjerne i en fil med et Bash-script, og en af måderne at gøre det på er at bruge en for loop.
Hvad er en for-loop?
En for-loop er en af de mest almindelige programmeringskonstruktioner, og den bruges til at udføre en given blok af kode givet et sæt elementer i en liste. Lad os f.eks. sige, at du ønsker at skrive et program, der udskriver antallet af personer, der bor i de 10 største europæiske byer. Programmet kan bruge en for-loop til at gennemgå hver by på listen og udskrive antallet af personer for den pågældende by.
Logikken, der udføres, er hver gang den samme, og det eneste, der ændres, er byen.
Nedenfor kan du se den generiske syntaks for en Bash for-loop:
for item in do command1 command2 ... commandNdone
LIST kan f.eks. være:
- en række af tal.
- en sekvens af strenge adskilt af mellemrum.
- outputtet fra en Linux-kommando (f.eks. kommandoen ls).
De N kommandoer mellem do og done udføres for hvert element i listen.
For Loop i Bash
I denne artikel lærer du, hvordan du bruger for loopet i Bash og specifikt til at gå igennem linjerne i en fil.
Men hvorfor skulle du gøre det? At gå igennem linjerne i en fil?
For eksempel kan du have brug for at gøre det, hvis du har eksporteret data fra et program til en fil, og du ønsker at udarbejde disse data på en eller anden måde.
I dette eksempel vil vi bruge en simpel .txt-fil, hvor hver linje indeholder:
- navnet på en by
- antallet af personer, der bor i den pågældende by.
Nedenfor kan du se formatet af tekstfilen, et kolon bruges til at adskille hver by fra antallet af personer, der bor i den pågældende by:
Istanbul:15,067,724Moscow:12,615,279London:9,126,366...
Så, hvordan kan vi bruge en Bash for loop til at gå igennem indholdet af denne fil?
Først gemmer vi navnet på filen i en variabel
FILENAME="european-cities.txt"
Dernæst bruger vi en anden variabel og kommandoen cat til at få alle linjerne i filen:
LINES=$(cat $FILENAME)
Her bruger vi kommandosubstitution til at tildele output fra cat-kommandoen til LINES-variablerne.
Finalt giver for-løjfen mulighed for at gennemgå hver linje i filen:
for LINE in $LINESdo echo "$LINE"done
Do og done bruges til at definere de kommandoer, der skal udføres ved hver iteration af for-løjfen.
For eksempel, hvis du har en fil med 10 linjer, vil for-loop’en gå gennem 10 iterationer, og ved hver iteration vil den læse én linje i filen.
Echo-kommandoen kan erstattes af en hvilken som helst sekvens af kommandoer baseret på, hvad du ønsker at gøre med hver linje i filen.
Her er det endelige script:
#!/bin/bash FILENAME="european-cities.txt"LINES=$(cat $FILENAME)for LINE in $LINESdo echo "$LINE"done
Og scriptets output er…
./cities.sh Istanbul:15,067,724Moscow:12,615,279London:9,126,366Saint-Petersburg:5,383,890Berlin:3,748,148Kyiv:3,703,100Madrid:3,223,334Rome:2,857,321Paris:2,140,526Bucharest:2,106,144
Vi videregiver listen til for-løjpen ved hjælp af kommandoen cat.
Det betyder, at vi kan bruge alle de kommandoer, vi ønsker, til at generere den LISTE, der skal videregives til for-løjpen.
Har du andre mulige kommandoer i tankerne?
Dertil kommer, at for-sløjfen ikke er den eneste mulighed for at oprette en sløjfe i et Bash-script, en anden mulighed er en while-sløjfe.
Hvad er en tæller i en for-sløjfe i Bash?
I en for-sløjfe kan du også definere en variabel, der hedder counter. Du kan bruge en tæller til at spore hver iteration af løkken.
Brugen af en tæller er meget almindelig i alle programmeringssprog. Den kan også bruges til at få adgang til elementerne i en datastruktur inde i løkken (dette er ikke tilfældet i vores eksempel).
Lad os ændre det foregående program og definere en tæller, hvis værdi udskrives ved hver iteration:
#!/bin/bash FILENAME="european-cities.txt"LINES=$(cat $FILENAME)COUNTER=0for LINE in $LINESdo echo "Counter $COUNTER: $LINE" COUNTER=$((COUNTER+1))done
Som du kan se, har jeg defineret en variabel kaldet COUNTER uden for for-løjpen med dens startværdi sat til 0.
Derpå udskriver jeg ved hver iteration værdien af tælleren sammen med linjen fra filen.
Efter at have gjort det bruger jeg den aritmetiske operatør Bash til at øge værdien af variablen COUNTER med 1.
Og her er scriptets output:
Counter 0: Istanbul:15,067,724Counter 1: Moscow:12,615,279Counter 2: London:9,126,366Counter 3: Saint-Petersburg:5,383,890Counter 4: Berlin:3,748,148Counter 5: Kyiv:3,703,100Counter 6: Madrid:3,223,334Counter 7: Rome:2,857,321Counter 8: Paris:2,140,526Counter 9: Bucharest:2,106,144
Break og Continue i en Bash For Loop
Der er måder at ændre det normale flow i en for loop i Bash på.
De to statements, der gør det muligt, er break og continue:
- break: afbryder udførelsen af for loopet og springer til den første linje efter for loopet.
- continue: springer til den næste gentagelse af for-loop’en.
Da vi har defineret en tæller, kan vi se, hvad der sker, når vi tilføjer break eller continue til vores eksisterende script.
Lad os starte med break…
Jeg vil tilføje en if-anvisning baseret på værdien af tælleren. Break-erklæringen inde i if’en afbryder udførelsen af løkken, hvis tælleren er lig med 3:
#!/bin/bash FILENAME="european-cities.txt"LINES=$(cat $FILENAME)COUNTER=0for LINE in $LINESdo if ; then break fi echo "Counter $COUNTER: $LINE" COUNTER=$((COUNTER+1))done
Og output er:
Counter 0: Istanbul:15,067,724Counter 1: Moscow:12,615,279Counter 2: London:9,126,366
Som du kan se, stopper break-erklæringen udførelsen af for-løkken, før den når frem til ekko-kommandoen, fordi tælleren er 3.
Så lad os erstatte break med continue og se, hvad der sker. Jeg lader resten af koden forblive uændret.
#!/bin/bash FILENAME="european-cities.txt"LINES=$(cat $FILENAME)COUNTER=0for LINE in $LINESdo if ; then continue fi echo "Counter $COUNTER: $LINE" COUNTER=$((COUNTER+1))done
Og her er outputtet for scriptet:
Counter 0: Istanbul:15,067,724Counter 1: Moscow:12,615,279Counter 2: London:9,126,366
Mærkeligt…outputtet er det samme. Hvorfor?
Det skyldes, at når værdien af COUNTER er 3, springer continue-erklæringen til den næste iteration af løkken, men den øger ikke værdien af tælleren.
Så ved den næste iteration er værdien af COUNTER stadig 3, og continue-erklæringen udføres igen, og sådan fortsætter det for alle de andre iterationer.
For at løse dette skal vi øge værdien af variablen COUNTER inde i if-erklæringen:
#!/bin/bash FILENAME="european-cities.txt"LINES=$(cat $FILENAME)COUNTER=0for LINE in $LINESdo if ; then COUNTER=$((COUNTER+1)) continue fi echo "Counter $COUNTER: $LINE" COUNTER=$((COUNTER+1))done
Denne gang ser vi det korrekte output:
Counter 0: Istanbul:15,067,724Counter 1: Moscow:12,615,279Counter 2: London:9,126,366Counter 4: Berlin:3,748,148Counter 5: Kyiv:3,703,100Counter 6: Madrid:3,223,334Counter 7: Rome:2,857,321Counter 8: Paris:2,140,526Counter 9: Bucharest:2,106,144
Som du kan se, bliver “Counter 3: ….” ikke udskrevet i terminalen.
Skrivning af en For-loop i én linje
Før vi afslutter denne tutorial, skal vi se, hvordan vi kan skrive en For-loop i én linje.
Dette er ikke en anbefalet praksis, da det gør din kode mindre læsbar.
Men det er godt at vide, hvordan man skriver en loop i én linje, det giver mere dybde til din Bash-viden.
Den generiske syntaks for en Bash for-loop i én linje er følgende:
for i in ; do ; done
Lad os udskrive indholdet af vores tekstfil med en for-loop på én linje:
#!/bin/bashFILENAME="european-cities.txt"LINES=$(cat $FILENAME)for LINE in $LINES; do echo $LINE; done
For at forenkle tingene har jeg fjernet COUNTER og if-erklæringen. Hvis de var der, ville den enlinede for-sløjfe være meget sværere at læse.
Prøv at holde dig væk fra enlinede sætninger, hvis de gør din kode svær at læse.
Slutning
Sammenfattende har du i denne vejledning lært at:
- Lagre linjerne i en fil i en variabel
- Brug en for-sløjfe til at gå igennem hver linje.
- Brug en tæller i en for-sløjfe.
- Forandre flowet i en sløjfe med break og continue.
- Skriv en for-sløjfe i én linje.
Giver det mening?
Hvordan vil du bruge dette?
Lad mig vide det 🙂
Hvis du vil lære mere om loops i Bash scripting skal du kigge på denne tutorial.
Relateret GRATIS kursus: Decipher Bash Scripting