För och läs-öglor i Bash

Hur man slingrar, aka utforma ett program för att göra repetitivt arbete åt dig

Slingan är en av de mest grundläggande och kraftfulla konstruktionerna inom databehandling, eftersom den gör det möjligt för oss att upprepa en uppsättning kommandon, så många gånger vi vill, på en lista över objekt som vi väljer. Mycket av beräkningstänkandet handlar om att ta en uppgift och lösa den på ett sätt som kan tillämpas upprepade gånger på alla andra liknande uppgifter, och for-loop är hur vi får datorn att göra det repetitiva arbetet:

Till skillnad från det mesta av koden vi hittills har skrivit vid den interaktiva prompten körs en for-loop inte så snart vi trycker på Enter:

Vi kan skriva ut så många kommandon som vi vill i blocket mellan nyckelorden do och done :

Endast tills vi når done och trycker på Enter, gör for-loop sitt arbete.

Detta är fundamentalt annorlunda än det rad-för-rad-kommando-och-svaret vi hittills har upplevt vid uppmaningen. Och det förutser hur vi kommer att programmera vidare: mindre tonvikt på att utföra kommandon med varje rad och mer tonvikt på att planera funktionerna i ett program och sedan köra det senare.

Grundläggande syntax

Syntaxen för for loopar kan vara förvirrande, så här är några grundläggande exempel för att förbereda / uppdatera din förståelse av dem:

Här ”är en mer detaljerad version med variabler:

En kommandosubstitution kan användas för att generera de objekt som for slingan itererar över:

Om du behöver läsa en lista med rader från en fil, och är helt säkra på att ingen av raderna innehåller ett mellanslag inom dem:

En läs-slinga är en variant av ovan, men är säkrare för att läsa rader från en fil:

Konstruera en bas för loop

Låt oss börja från början, med en mycket minimal for slinga och byggde den sedan in i något mer detaljerat för att hjälpa oss att förstå deras syfte.

Den enklaste slingan

Det här är ungefär lika enkelt som du kan skapa en for loop:

Verkade det ganska värdelöst? Ja det borde ha. Jag skrev fyra rader kod för att göra vad som krävs för en enda rad, echo "Hi".

Fler element i samlingen

Det ”Det är svårt att säga, men en” loop ”kördes. Den kördes bara en gång. OK, så hur får vi den att köra mer än en gång? Lägg till fler (mellanslag) element till höger om in nyckelord. Låt oss lägga till ytterligare fyra 1 ”s:

OK, inte särskilt spännande, men programmet verkade definitivt åtminstone slinga: fyra 1 ”resulterade i att fyra echo kommandon kördes.

Vad händer när vi ersätter de fyra 1 ”med olika siffror? Och kanske ett par ord?

Och … ingenting. Så slingan gör inte automatiskt något specifikt för samlingen av värden vi gav den. Inte ändå än.

Se loop-variabeln

Låt oss se till vänster om in nyckelordet, och därpå x. Vad är poängen med den x? En gemener x är inte namnet på ett nyckelord eller kommando som vi hittills har stött på (och att utföra det ensamt vid uppmaningen kommer att orsaka ett fel). Så det är kanske en variabel? Låt oss försöka referera till den i echo uttalande:

Bingo. Detta är i stort sett de grundläggande funktionerna för en for loop: – Få en samling objekt / värden (Q Zebra 999 Smithsonian) – Skicka dem till en for loop-konstruktion – Använd loop-variabeln (x) som platshållare och skriv kommandon mellan do / done block. – När slingan körs tar slingvariabeln, x värdet för var och en av objekten i listan – Q, Zebra, 999, Smithsonian, – och kommandoblocket mellan do och done körs sedan. Denna sekvens upprepas en gång för varje objekt i listan.

do / done -blocket kan innehålla valfri sekvens av kommandon, till och med en annan for -loop:

Slingor-inom-slingor är en vanlig konstruktion i programmering.För det mesta kommer jag att försöka undvika att tilldela problem som skulle involvera denna typ av logik, eftersom det kan vara svårt att vrida bort under felsökning.

Läs en fil, rad för rad, tillförlitligt med läs medan

Eftersom cat skriver ut en fil rad för rad verkar följande för loop förnuftigt:

Kommandosubstitutionen kommer dock att leda till att cat delar ord efter mellanslag. Om list-of-dirs.txt innehåller följande:

Utgången från for -slingan blir denna:

En läs-slinga kommer att bevara orden inom en rad:

Vi kan också pipa från resultatet av ett kommando genom att bifoga det i <( och ):

Rör och slingor

Om du kommer från andra språk kan dataströmmar vara okända för dig . Åtminstone är de för mig, eftersom syntaxen för att arbeta med dem är mycket mer direkt och okomplicerad i Bash än i Ruby eller Python.

Men om du är ny för programmering på något språk, vad kan det är också oklart hur arbetet med dataströmmar skiljer sig från att arbeta med slingor.

Till exempel följande kodavsnitt:

– producerar samma utgång som den här slingan:

Och beroende på din mentala modell av saker verkar det som om i båda exemplen, varje ord, t.ex. hello, world, skickas genom en översättningsprocess (via tr) och ekas sedan.

Rör och filter

Utan att gå in i Unix-systemets fundament, där ett rör fungerar fundamentalt annorlunda än en slinga här, låt mig föreslå en mental lösning:

Program som rör från stdin och stdout kan vanligtvis ordnas som filter, i vilka en dataström går in i ett program och kommer ut i ett annat format:

För uppgifter som är mer än bara att omvandla data, från filter till filter, tänk på att använda en loop. Vad kan till exempel en uppgift vara? Med en lista över webbadresser, ladda ner var och en och ladda ner den nedladdade informationen, med ett anpassat innehåll och ämne:

Datainmatningskällan, varje webbadress i urls.txt, filtreras inte verkligen här. Istället görs en flerstegsuppgift för varje webbadress.

Piping in read-while

Med detta sagt kan en loop i sig implementeras som bara ett filter till bland filtren. Ta den här varianten av läs-slingan, där resultatet av echo | grep rörs, rad för rad, in i while loop, som skrivs ut till stdout med echo, som omdirigeras till filen som heter some.txt:

Detta är inte en konstruktion som du kan behöva göra ofta, om alls, men förhoppningsvis förstärker det röranvändningen i Unix.

Mindre interaktiv programmering

frekvent användning av for loopar och liknande konstruktioner betyder att vi ”går över de goda ol” -dagarna för att skriva in en rad med c ommands och få den att köras direkt efter att vi tryckt på Enter. Oavsett hur många kommandon vi packar in i en for -slinga, händer ingenting förrän vi träffar sökordet done.

Skriv en gång. Slinga sedan igen

Med den förlusten av rad-för-rad-interaktion med skalet förlorar vi den största fördelen med den interaktiva prompten: omedelbar feedback. Och vi har fortfarande alla nackdelar: om vi gör ett skrivfel tidigare i kommandoblocket mellan do och done, måste vi börja överallt.

Så här mildrar vi det:

Testa din kod, ett fall i taget

Ett av de största misstagen nybörjare gör med for loopar är att de tror att en for loop löser omedelbart deras problem. Så om det de behöver göra är att ladda ner 10 000 webbadresser, men de kan inte ladda ner bara en webbadress ordentligt, de tycker att det är ett steg i rätt riktning att sätta sina felaktiga kommandon i en for -slinga.

Förutom att detta är en grundläggande missförstånd av en for slinga, det praktiska problemet är att du nu kör din trasiga kod 10 000 gånger, vilket innebär att du måste vänta 10 000 gånger så länge för att ta reda på att din kod är, Ack, fortfarande trasig.

Så låtsas att du ”aldrig har hört talas om for öglor. Låtsas att du måste ladda ner alla 10 000 webbadresser, ett kommando per gång. Kan du skriva kommandot för att göra det för den första URL: n. Vad sägs om den andra? När du väl är övertygad om att inga mindre syntaxfel snubblar dig, är det dags att fundera över hur man hittar ett allmänt mönster för 9 997 andra webbadresser.

Skriv manus

Den interaktiva kommandoraden är fantastisk.Det var kul att börja med, och det kommer att vara kul under hela din datorkarriär. Men när du har en stor uppgift framför dig, med mer än tio rader kod, är det dags att sätta den koden i en skalskript. Lita inte på dina felbara mänskliga fingrar för att felfritt skriva in koden.

Använd nano för att arbeta på öglor och spara dem som skal För längre filer kommer jag att arbeta på min dators textredigerare (sublim text) och sedan ladda upp till servern.

Träna med webbskrapning

Bara för att jorda syntax och funktion för for-loop, här är tankeprocessen från att omvandla en rutinuppgift till en loop:

För siffrorna 1 till 10, använd curl för att ladda ner Wikipedia-posten för varje nummer och spara den i en fil med namnet ”wiki-number-(whatever the number is).html

Det gammaldags sättet

Med bara 10 webbadresser kunde vi ställa in ett par variabler och sedan kopiera och klistra in a curl-kommandot, tio gånger, med ändringar i varje rad:

Och gissa vad? Det fungerar. För tio webbadresser är det inte en dålig lösning, och det är betydligt snabbare än att göra det på det gammaldags sättet (gör det från din webbläsare)

Minska repetition

Även utan att tänka på en loop kan vi fortfarande minska repetitionen med hjälp av variabler: bas-URL, , och basfilnamnet ändras aldrig, så låt oss tilldela dessa värden till variabler som kan återanvändas:

Tillämpa for-loop

Vid denna tidpunkt har vi förenklat mönstret så långt att vi kan se hur lite som förändras med varje separat uppgift. Efter att ha lärt oss om for -slingan kan vi använda den utan att tänka mycket (vi lägger också till ett vilokommando så att vi pausar mellan webbförfrågningar)

Generera en lista

I de flesta situationer är det enkelt att skapa en for-loop; det är skapandet av listan som kan vara det hårda arbetet. Vad händer om vi vill samla sidorna för siffrorna 1 till 100? Det är mycket att skriva.

Men om vi låter vår latskap diktera vårt tänkande kan vi föreställa oss att räkna från x till y verkar som en inneboende beräkningsuppgift. Och det är, och Unix har seq verktyget för detta:

Generera en lista med icke-nummer för iteration

Många repetitiva uppgifter är inte så enkelt som att räkna från x till y, och så blir problemet hur man skapar en icke-linjär lista över objekt? Det här är i princip vad konsten att samla in data och hantera. Men låt oss göra ett enkelt scenario för oss själva:

För tio av de 10 bokstäverna (eller fler) som visas minst en gång i en rubrik på den nuvarande NYTimes.com-förstasidan, hämta Wiktionary-sidan för det ordet

Vi delar uppgiften i två delar:

  1. Hämta en lista med tio 10 + -bokstavsord från nytimes.com-rubriker
  2. Skicka dessa ord till vår for-loop

Steg 1: Använd valpverktyget (eller kommandorads HTML-parser av ditt val):

Steg 2 (förutsatt att words -variabeln överförs):

Kolla in Softwa re Carpentry är en utmärkt guide till for-loopar i Bash

Leave a Reply

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *