Loop genom raderna i en fil: Bash For Loop Explained

Jag vill loopa genom raderna i en fil med ett Bash-skript och ett av sätten att göra det är att använda en for-slinga.

Vad är en for-slinga?

En for-slinga är en av de vanligaste programmeringskonstruktionerna och den används för att utföra ett visst kodblock givet en uppsättning objekt i en lista. Låt oss till exempel säga att du vill skriva ett program som skriver ut antalet personer som bor i de 10 största europeiska städerna. Programmet kan använda en for-slinga för att gå igenom varje stad i listan och skriva ut antalet personer för den staden.

Logiken som exekveras är varje gång densamma och det enda som ändras är staden.

Nedan kan du se den generiska syntaxen för en Bash for-slinga:

for item in do command1 command2 ... commandNdone

LIST kan till exempel vara:

  • ett intervall av siffror.
  • en sekvens av strängar separerade med blanksteg.
  • utmatningen från ett Linuxkommando (t.ex. kommandot ls).

N-kommandon mellan do och done utförs för varje objekt i listan.

For-slinga i Bash

I den här artikeln kommer du att lära dig hur du använder for-slingan i Bash och specifikt för att gå igenom raderna i en fil.

Men varför skulle du göra det? Gå igenom raderna i en fil?

Det kan du till exempel behöva göra om du har exporterat data från ett program till en fil och du vill bearbeta dessa data på något sätt.

I det här exemplet kommer vi att använda en enkel .txt-fil där varje rad innehåller:

  • namnet på en stad
  • antalet personer som bor i den staden.

Nedan kan du se formatet på textfilen, ett kolon används för att separera varje stad från antalet personer som bor i den staden:

Istanbul:15,067,724Moscow:12,615,279London:9,126,366... 

Så, hur kan vi använda en Bash for-slinga för att gå igenom innehållet i den här filen?

Först lagrar vi namnet på filen i en variabel

FILENAME="european-cities.txt"

Därefter använder vi en annan variabel och kommandot cat för att få fram alla rader i filen:

LINES=$(cat $FILENAME)

Här använder vi kommandosubstitution för att tilldela utmatningen från kommandot cat till variablerna LINES.

Slutligt gör for-slingan det möjligt att gå igenom varje rad i filen:

for LINE in $LINESdo echo "$LINE"done

Do och done används för att definiera de kommandon som ska utföras vid varje iteration av for-slingan.

Till exempel, om du har en fil med 10 rader kommer for-slingan att gå igenom 10 iterationer och vid varje iteration kommer den att läsa en rad i filen.

Echo-kommandot kan ersättas med vilken sekvens av kommandon som helst baserat på vad du vill göra med varje rad i filen.

Här är det slutliga skriptet:

#!/bin/bash FILENAME="european-cities.txt"LINES=$(cat $FILENAME)for LINE in $LINESdo echo "$LINE"done

Och utmatningen av skriptet är…

./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 överlämnar listan till for-slingan med hjälp av kommandot cat.

Detta innebär att vi kan använda vilka kommandon som helst för att generera LISTEN som ska överlämnas till for-slingan.

Har du några andra möjliga kommandon i åtanke?

Det är också så att for-slingan inte är det enda alternativet för att skapa en slinga i ett Bash-skript, ett annat alternativ är en while-slinga.

Vad är en räknare i en for-slinga i Bash?

I en for-slinga kan du också definiera en variabel som heter counter. Du kan använda en räknare för att spåra varje iteration av slingan.

Användningen av en räknare är mycket vanlig i alla programmeringsspråk. Den kan också användas för att få tillgång till elementen i en datastruktur inne i slingan (detta är inte fallet i vårt exempel).

Låt oss ändra det föregående programmet och definiera en räknare vars värde skrivs ut vid varje 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 jag definierat en variabel som heter COUNTER utanför for-slingan med dess initiala värde satt till 0.

Därefter skriver jag vid varje iteration ut värdet på räknaren tillsammans med raden från filen.

Efter att ha gjort det använder jag den aritmetiska operatorn Bash för att öka värdet på variabeln COUNTER med 1.

Och här är utdata från skriptet:

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

Bryt och fortsätt i en Bash-for-slinga

Det finns sätt att ändra det normala flödet av en for-slinga i Bash.

De två uttalanden som gör det möjligt att göra det är break och continue:

  • break: avbryter utförandet av for-slingan och hoppar till den första raden efter for-slingan.
  • continue: hoppar till nästa iteration av for-slingan.

Att ha definierat en räknare hjälper oss att se vad som händer när vi lägger till break eller continue till vårt befintliga skript.

Låt oss börja med break…

Jag kommer att lägga till ett if-uttalande baserat på värdet av räknaren. Break-anvisningen inuti if bryter exekveringen av slingan om räknaren är lika 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

Och utmatningen är:

Counter 0: Istanbul:15,067,724Counter 1: Moscow:12,615,279Counter 2: London:9,126,366

Som du kan se stoppar break-anvisningen exekveringen av for-slingan innan den når eko-kommandot eftersom COUNTER är 3.

Och låt oss ersätta break med continue och se vad som händer. Jag lämnar resten av koden oförändrad.

#!/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

Och här är utmatningen för skriptet:

Counter 0: Istanbul:15,067,724Counter 1: Moscow:12,615,279Counter 2: London:9,126,366

Märkligt…utmatningen är densamma. Varför?

Det beror på att när värdet på COUNTER är 3 hoppar continue-anvisningen till nästa iteration av slingan, men den ökar inte värdet på räknaren.

Så vid nästa iteration är värdet på COUNTER fortfarande 3 och continue-anvisningen körs igen, och så vidare för alla andra iterationer.

För att åtgärda detta måste vi öka värdet på variabeln COUNTER inne i if-anvisningen:

#!/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

Denna gång ser vi den korrekta utmatningen:

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 skrivs inte ”Counter 3: ….” ut i terminalen.

Skrivning av en for-slinga på en rad

För att avsluta den här handledningen ska vi se hur vi kan skriva en for-slinga på en rad.

Det här är inte en rekommenderad praxis med tanke på att det gör din kod mindre lättläst.

Men det är bra att veta hur man skriver en slinga på en rad, det ger mer djup åt din Bash-kunskap.

Den generiska syntaxen för en Bash for-slinga på en rad är följande:

for i in ; do ; done

Låt oss skriva ut innehållet i vår textfil med en for-slinga på en rad:

#!/bin/bashFILENAME="european-cities.txt"LINES=$(cat $FILENAME)for LINE in $LINES; do echo $LINE; done

För att förenkla har jag tagit bort COUNTER och if-angivelsen. Om de fanns där skulle den enradiga for-slingan vara mycket svårare att läsa.

Försök att hålla dig borta från enradiga om de gör din kod svårläst.

Slutsats

Slutningsvis har du i den här handledningen lärt dig hur man:

  1. lagrar en fils rader i en variabel
  2. använder en for-slinga för att gå igenom varje rad.
  3. Använda en räknare i en for-slinga.
  4. Ändra flödet i en slinga med break och continue.
  5. Skriva en for-slinga på en rad.

Är det vettigt?

Hur ska du använda det här?

Låt mig veta 🙂

Om du vill lära dig mer om slingor i Bash-skript kan du ta en titt på den här handledningen.

Relaterad gratis kurs: Dechiffrera Bash Scripting

Lämna ett svar

Din e-postadress kommer inte publiceras.