For og read-While-sløjfer i Bash

Sådan løkker du, aka designe et program til at udføre gentagne arbejder for dig

Sløjfen er en af de mest grundlæggende og kraftfulde konstruktioner inden for computing, fordi den giver os mulighed for at gentage et sæt kommandoer, så mange gange vi ønsker, på en liste over emner, vi vælger. Meget af beregningstænkning indebærer at tage en opgave og løse den på en måde, der kan anvendes gentagne gange på alle andre lignende opgaver, og for-loop er, hvordan vi får computeren til at gentage det arbejde:

I modsætning til det meste af den kode, vi hidtil har skrevet ved den interaktive prompt, udføres en for-loop ikke, så snart vi rammer Enter:

Vi kan skrive så mange kommandoer ud, som vi vil, i blokken mellem nøgleordene do og done :

Kun indtil vi når done, og trykker Enter, gør for-loop sit arbejde.

Dette er grundlæggende forskelligt fra den linje-for-linje kommando-og-respons, vi hidtil har oplevet på anmodningen. Og det forudsætter, hvordan vi vil programmere videre: mindre vægt på at udføre kommandoer med hver linje og mere vægt på at planlægge funktionerne i et program og derefter udføre det senere.

Grundlæggende syntaks

Syntaksen for for sløjfer kan være forvirrende, så her er nogle grundlæggende eksempler til forberedelse / opdatering af din forståelse af dem:

Her “er en mere detaljeret version ved hjælp af variabler:

En kommandosubstitution kan bruges til at generere de emner, som for -sløjfen gentager:

Hvis du har brug for at læse en liste med linjer fra en fil, og er helt sikre på, at ingen af linjerne indeholder et mellemrum i dem:

En read-while-loop er en variation af ovenstående, men er sikrere til læsning af linjer fra en fil:

Konstruktion af en basis til loop

Lad os starte fra en begyndelse med en meget minimal for sløjfe, og byggede den derefter ind i noget mere detaljeret for at hjælpe os med at få en forståelse af deres formål.

Den enkleste sløjfe

Dette er omtrent lige så simpelt som du kan lave en for loop:

Virkede det ret værdiløst? Ja det burde have. Jeg skrev fire linjer kode for at gøre, hvad der kræves for en enkelt linje, echo "Hi".

Flere elementer i samlingen

Det “Det er svært at fortælle, men en” loop “blev udført. Det blev bare udført en gang. OK, så hvordan får vi det til at udføre mere end én gang? Tilføj flere (mellemrumsadskilte) elementer til højre for in nøgleord. Lad os tilføje fire mere 1 “s:

OK, ikke særlig spændende, men programmet syntes bestemt i det mindste at løbe: fire 1 “s resulterede i, at fire echo kommandoer blev udført.

Hvad sker der, når vi erstatter disse fire 1 “med forskellige tal? Og måske et par ord?

Og … intet. Så sløjfen gør ikke automatisk noget specifikt for den samling af værdier, vi gav det. Ikke alligevel endnu.

Se loop-variablen

Lad os se til venstre for in nøgleordet, og på det x. Hvad er pointen med den x? En lille bogstav x er ikke navnet på et nøgleord eller en kommando, som vi hidtil har stødt på (og at udføre det alene ved prompten vil give en fejl). Så måske er det en variabel? Lad os prøve at henvise til den i echo udsagnet:

Bingo. Dette er stort set den grundlæggende funktion af en for loop: – Få en samling af emner / værdier (Q Zebra 999 Smithsonian) – Giv dem til en for loop-konstruktion – Brug loop-variablen (x) som pladsholder, skriv kommandoer mellem do / done blok. – Når sløjfen udføres, tager sløjfevariablen x værdien af hvert af elementerne i listen – Q, Zebra, 999, Smithsonian, – og kommandoblokken mellem do og done udføres derefter. Denne sekvens gentages en gang for hvert element på listen.

do / done -blokken kan indeholde en hvilken som helst sekvens af kommandoer, endda en anden for -loop:

Sløjfer inden for sløjfer er en almindelig konstruktion i programmering.For det meste vil jeg forsøge at undgå at tildele problemer, der vil involvere denne form for logik, da det kan være vanskeligt at afvikle under fejlretning.

Læs en fil, linje for linje, pålideligt med read-while

Fordi cat udskriver en fil linje for linje, synes følgende for loop fornuftigt:

Kommandosubstitutionen får dog cat til at opdele ord efter mellemrum. Hvis list-of-dirs.txt indeholder følgende:

Outputtet fra for -sløjfen bliver dette:

En read-while-sløjfe bevarer ordene inden for en linje:

Vi kan også pibe fra resultatet af en kommando ved at omslutte den i <( og ):

Rør og sløjfer

Hvis du kommer fra andre sprog, kan datastrømme være ukendte for dig . I det mindste er de for mig, da syntaksen for at arbejde med dem er langt mere direkte og ligetil i Bash end i Ruby eller Python.

Men hvis du er ny til programmering på et hvilket som helst sprog, hvad kan også være uklar er, hvordan arbejde med datastrømme er anderledes end at arbejde med sløjfer.

For eksempel følgende uddrag:

– producerer den samme output som denne sløjfe:

Og afhængigt af din mentale model af ting ser det ud til, at i begge eksempler, hvert ord, f.eks. hello, world, føres gennem en oversættelsesproces (via tr) og gentages derefter.

Rør og filtre

Uden at komme ind i fundamentet i Unix-systemet, hvor et rør fungerer fundamentalt anderledes end en løkke her, lad mig foreslå en mental løsning:

Programmer, der rører fra stdin og stdout, kan normalt arrangeres som filtre, hvor en strøm af data er går ind i et program og kommer ud i et andet format:

For opgaver, der mere end bare transformerer data, fra filter til filter, skal du overveje at bruge en sløjfe. Hvad kan f.eks. En opgave være? Givet en liste over webadresser, skal du downloade hver og sende de downloadede data via e-mail med et tilpasset brødtekst og emne:

Datainputkilden, hver URL i urls.txt, bliver ikke virkelig filtreret her. I stedet udføres en flertrinsopgave for hver URL.

Piping til read-while

Når det er sagt, kan en loop selv implementeres som blot endnu et filter blandt filtre. Tag denne variation af read-while-sløjfen, hvor resultatet af echo | grep ledes linje for linje ind i while loop, der udskrives til stdout ved hjælp af echo, som omdirigeres til filen med navnet some.txt:

Dette er ikke en konstruktion, som du muligvis skal gøre ofte, overhovedet, men forhåbentlig styrker det rørforbruget i Unix.

Mindre interaktiv programmering

hyppig brug af for sløjfer og lignende konstruktioner betyder, at vi “bevæger os forbi de gode ol” dage med at skrive en linje med c ommands og få det til at køre lige efter vi har ramt Enter. Uanset hvor mange kommandoer vi pakker i en for loop, sker der intet, før vi rammer nøgleordet done.

Skriv en gang. Derefter sløjfer det

Med det tab af linje-for-linje-interaktion med skallen mister vi den største fordel ved den interaktive prompt: øjeblikkelig feedback. Og vi har stadig alle ulemperne: Hvis vi laver en tastefejl i kommandoblokken mellem do og done, er vi nødt til at starte overalt.

Så her mildrer vi det:

Test din kode, en sag ad gangen

En af de største fejl, novicerne laver med for sløjfer er, at de mener, at en for løkke straks løser deres problem. Så hvis det, de skal gøre, er at downloade 10.000 webadresser, men de kan ikke korrekt downloade kun én URL, de tror, at det er et skridt i den rigtige retning at sætte deres fejlbehæftede kommandoer i en for -sløjfe.

Udover at dette er en grundlæggende misforståelse af en for -sløjfe, er det praktiske problem, at du nu kører din ødelagte kode 10.000 gange, hvilket betyder at du skal vente 10.000 gange så længe for at finde ud af, at din kode er, ak, stadig brudt.

Så lad som om du “aldrig har hørt om for sløjfer. Lad som om du skal downloade alle 10.000 webadresser, en kommando ad gangen. Kan du skrive kommandoen for at gøre det til den første URL. Hvad med det andet? Når du er “rimelig sikker på, at ingen mindre syntaksfejl udløser dig, er det tid til at tænke på, hvordan man finder et generelt mønster til de 9.997 andre webadresser.

Skriv scripts

Den interaktive kommandolinje er fantastisk.Det var sjovt at starte med, og det bliver sjovt i hele din computerkarriere. Men når du har en stor opgave foran dig, der involverer mere end ti linjer kode, er det tid til at sætte koden i en shell-script. Stol ikke på dine fejlbare menneskelige fingre til fejlfrit at indtaste koden igen.

Brug nano til at arbejde på sløjfer og gem dem som skal For længere filer vil jeg arbejde på min computers teksteditor (sublim tekst) og derefter uploade til serveren.

Træning med webskrabning

Bare for at jorde syntaks og funktion af for-loop, her er tankeprocessen fra at omdanne en rutineopgave til en loop:

For tallene 1 til 10, Brug krølle til at downloade Wikipedia-posten for hvert nummer, og gem det i en fil med navnet “wiki-number-(whatever the number is).html

Den gammeldags måde

Med kun 10 webadresser kunne vi indstille et par variabler og derefter kopiere og indsætte kommandoen a curl 10 gange og foretage ændringer i hver linje:

Og gæt hvad? Det virker. For 10 URL’er er det ikke en dårlig løsning, og det er betydeligt hurtigere end at gøre det på den gammeldags måde (gør det fra din webbrowser)

Reduktion af gentagelse

Selv uden at tænke på en løkke, kan vi stadig reducere gentagelse ved hjælp af variabler: basis-URL, , og basisfilnavnet ændres aldrig, så lad os tildele disse værdier til variabler der kan genbruges:

Anvendelse af for-loop

På dette tidspunkt har vi forenklet mønsteret så langt, at vi kan se, hvor lidt der ændres med hver enkelt opgave. Efter at have lært om for -loop, kan vi anvende den uden meget eftertanke (vi tilføjer også en søvnkommando, så vi stopper mellem webanmodninger)

Generering af liste

I de fleste situationer er det let at oprette en for-loop; det er oprettelsen af listen, der kan være det hårde arbejde. Hvad hvis vi ville samle siderne til nummer 1 til 100? Det er meget at skrive.

Men hvis vi lader vores dovenskab diktere vores tænkning kan vi forestille os, at tælle fra x til y virker som en iboende beregningsopgave. Og det er det, og Unix har seq -værktøjet til dette:

Generering af en liste med ikke-tal til iteration

Mange gentagne opgaver er ikke så simpelt som at tælle fra x til y, og så bliver problemet, hvordan man genererer en ikke-lineær liste over emner? Dette er dybest set, hvad kunsten at indsamle og administrere data. Men lad os lave et simpelt scenario for os selv:

For ti af ordene på 10 bogstaver (eller flere), der vises mindst en gang i en overskrift på den aktuelle NYTimes.com-forside, hent Wiktionary-siden til det ord

Vi deler denne opgave i to dele:

  1. Hent en liste på ti 10 + -bogstavord fra nytimes.com-overskrifter
  2. Send disse ord til vores for-loop

Trin 1: Brug af pup-hjælpeprogrammet (eller kommandolinjens HTML-parser af dit valg):

Trin 2 (forudsat at variablen words sendes videre):

Tjek Softwa re Carpentry’s fremragende guide til for-loops i Bash

Leave a Reply

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *