For og lese-mens sløyfer i Bash

Slik sløyfer du, aka designe et program for å gjøre repeterende arbeid for deg

Sløyfen er en av de mest grunnleggende og kraftige konstruksjonene innen databehandling, fordi den lar oss gjenta et sett med kommandoer, så mange ganger vi vil, på en liste over elementer vi velger. Mye av beregningstenking innebærer å ta en oppgave og løse den på en måte som kan brukes gjentatte ganger på alle andre lignende oppgaver, og for loop er hvordan vi får datamaskinen til å gjøre det repetitive arbeidet:

I motsetning til det meste av koden vi har skrevet hittil ved den interaktive ledeteksten, utføres ikke en for-loop så snart vi trykker Enter:

Vi kan skrive ut så mange kommandoer vi vil i blokken mellom do og done søkeord :

Bare til vi når done, og trykker Enter, gjør for-loop sitt arbeid.

Dette er fundamentalt annerledes enn kommandosvaret vi har opplevd så langt ved ledeteksten. Og det presiserer hvordan vi skal programmere videre: mindre vekt på å utføre kommandoer med hver linje, og mer vekt på å planlegge funksjonaliteten til et program, og deretter utføre det senere.

Grunnleggende syntaks

Syntaksen for for sløyfer kan være forvirrende, så her er noen grunnleggende eksempler for å forberede / oppdatere forståelsen av dem:

Her «er en mer forseggjort versjon med variabler:

En kommandosubstitusjon kan brukes til å generere elementene som for sløyfen itererer over:

Hvis du trenger å lese en liste over linjer fra en fil, og er helt sikre på at ingen av linjene inneholder et mellomrom i dem:

En lese-sløyfe er en variant av det ovennevnte, men er tryggere for å lese linjer fra en fil:

Konstruere en grunnleggende for loop

La oss starte fra en begynnelse, med en veldig minimal for sløyfe, og bygde den deretter inn i noe mer forseggjort, for å hjelpe oss med å få en forståelse av deres formål.

Den enkleste sløyfen

Dette er omtrent like enkelt som du kan lage en for loop:

Virket det ganske verdiløst? Ja det burde ha. Jeg skrev fire linjer med kode for å gjøre det som skal til for en enkelt linje, echo "Hi".

Flere elementer i samlingen

Det «Det er vanskelig å fortelle, men en» løkke «ble utført. Den ble bare utført en gang. OK, så hvordan får vi den til å utføre mer enn en gang? Legg til flere (mellomromsseparerte) elementer til høyre for in nøkkelord. La oss legge til fire til 1 «s:

OK, ikke veldig spennende, men programmet virket definitivt i det minste løkke: fire 1 «s resulterte i at fire echo kommandoer ble utført.

Hva skjer når vi erstatter de fire 1 «med forskjellige tall? Og kanskje et par ord?

Og … ingenting. Så sløyfen gjør ikke automatisk noe spesifikt for samlingen av verdier vi ga den. Ikke ennå uansett.

Se loop-variabelen

La oss se til venstre for in søkeordet, og på det x. Hva er poenget med den x? En liten bokstav x er ikke navnet på et nøkkelord eller en kommando som vi har opplevd så langt (og å utføre det alene på forespørsel vil gi en feil). Så kanskje det er en variabel? La oss prøve å referere til den i echo uttalelsen:

Bingo. Dette er ganske mye den grunnleggende funksjonen til en for loop: – Få en samling av elementer / verdier (Q Zebra 999 Smithsonian) – Gi dem til en for loop-konstruksjon – Bruk loop-variabelen (x) som plassholder, skriv kommandoer mellom do / done -blokk. – Når sløyfen kjøres, tar sløyfevariabelen x verdien av hvert av elementene i listen – Q, Zebra, 999, Smithsonian, – og kommandoblokken mellom do og done blir deretter utført. Denne sekvensen gjentas en gang for hvert element i listen.

do / done -blokken kan inneholde hvilken som helst sekvens av kommandoer, til og med en annen for -loop:

Loops-in-loops er en vanlig konstruksjon i programmering.For det meste vil jeg prøve å unngå å tilordne problemer som vil innebære denne typen logikk, da det kan være vanskelig å vri på under feilsøking.

Les en fil, linje for linje, pålitelig med lesing

Fordi cat skriver ut en fil linje for linje, virker følgende for loop fornuftig:

Kommandosubstitusjonen vil imidlertid føre til at cat deler ord etter mellomrom. Hvis list-of-dirs.txt inneholder følgende:

Utgangen fra for sløyfen vil være denne:

En leseløyfe vil bevare ordene innenfor en linje:

Vi kan også pipe fra resultatet til en kommando ved å legge den inn i <( og ):

Rør og sløyfer

Hvis du kommer fra andre språk, kan datastrømmer være ukjente for deg . I det minste er de for meg, ettersom syntaksen for å jobbe med dem er langt mer direkte og grei i Bash enn i Ruby eller Python.

Men hvis du er ny i programmering på noe språk, hva kan også være uklar er hvordan arbeid med datastrømmer er annerledes enn å jobbe med sløyfer.

For eksempel følgende kodebit:

– gir samme utgang som denne sløyfen:

Og avhengig av din mentale modell av ting, ser det ut til at i begge eksemplene, hvert ord, f.eks. hello, world, blir sendt gjennom en prosess for oversettelse (via tr) og ekko deretter.

Rør og filtre

Uten å komme inn i det grunnleggende i Unix-systemet, der et rør fungerer fundamentalt annerledes enn en løkke her, la meg foreslå en mental løsning:

Programmer som rør fra stdin og stdout kan vanligvis ordnes som filtre, der en datastrøm er tilgjengelig går inn i et program, og kommer ut i et annet format:

For oppgaver som er mer enn bare å transformere data, fra filter til filter, tenk å bruke en løkke. Hva kan for eksempel en oppgave være? Gitt en liste over nettadresser, last ned hver og e-post nedlastede data, med et tilpasset brødtekst og emne:

Datakilden, hver URL i urls.txt, blir ikke virkelig filtrert her. I stedet blir det utført en flertrinnsoppgave for hver URL.

Piping in read-while

Når det er sagt, kan en loop også implementeres som bare ett filter til blant filtrene. Ta denne variasjonen av lese-sløyfen, der resultatet av echo | grep ledes, linje for linje, inn i while loop, som skrives ut til stdout ved hjelp av echo, som blir omdirigert til filen som heter some.txt:

Dette er ikke en konstruksjon som du kanskje trenger å gjøre ofte, i det hele tatt, men forhåpentligvis forsterker det rørbruken i Unix.

Mindre interaktiv programmering

hyppig bruk av for sløyfer og lignende konstruksjoner, betyr at vi beveger oss forbi de gode dagene med å skrive inn en linje med c ommandene og få den til å kjøre rett etter at vi trykket Enter. Uansett hvor mange kommandoer vi pakker i en for loop, skjer det ingenting før vi treffer nøkkelordet done.

Skriv en gang. Sløyf den deretter

Med det tapet av linje-for-linje-interaksjon med skallet, mister vi hovedfordelen med den interaktive ledeteksten: umiddelbar tilbakemelding. Og vi har fortsatt alle ulempene: hvis vi skriver en feil tidligere i blokken av kommandoer mellom do og done, må vi starte overalt.

Så her reduserer vi det:

Test koden din, en sak om gangen

En av de største feilene nybegynnere gjør med for løkker er at de tror at en for løkke umiddelbart løser problemet deres. Så hvis det de må gjøre er å laste ned 10.000 nettadresser, men de kan ikke laste ned bare én URL, de tror å sette sine feilkommandoer i en for loop er et skritt i riktig retning.

I tillegg til at dette er en grunnleggende misforståelse av en for løkke, er det praktiske problemet at du nå kjører den ødelagte koden din 10 000 ganger, noe som betyr at du må vente 10 000 ganger så lenge for å finne ut at koden din er, akk, fremdeles ødelagt.

Så late som du «aldri har hørt om for løkker. Lat som om du må laste ned alle 10.000 nettadresser, en kommando om gangen. Kan du skrive kommandoen for å gjøre det for den første URL-en. Hva med det andre? Når du er rimelig sikker på at ingen mindre syntaksfeil utløser deg, er det på tide å tenke på hvordan du finner et generelt mønster for 9.997 andre nettadresser.

Skriv skript

Den interaktive kommandolinjen er flott.Det var morsomt å begynne med, og det vil være gøy gjennom hele din databehandlingskarriere. Men når du har en stor oppgave foran deg, som involverer mer enn ti linjer med kode, er det på tide å sette den koden i en skallskript. Ikke stol på de feilbare menneskelige fingrene dine til å skrive feil kode feilfritt.

Bruk nano til å jobbe på løkker og lagre dem som skall For lengre filer, vil jeg jobbe på datamaskinens tekstredigerer (Sublime Text) og deretter laste opp til serveren.

Trening med nettskraping

Bare for å jorde syntaks og arbeid for for-loop, her er tankeprosessen fra å gjøre en rutineoppgave til en loop:

For tallene 1 til 10, bruk krøll for å laste ned Wikipedia-oppføringen for hvert nummer, og lagre den i en fil som heter «wiki-number-(whatever the number is).html»

Den gammeldags måten

Med bare 10 nettadresser, kunne vi angi et par variabler og deretter kopiere og lime inn en krøllkommando, ti ganger, og gjøre endringer i hver linje:

Og gjett hva? Det fungerer. For 10 nettadresser er det ikke en dårlig løsning, og det er betydelig raskere enn å gjøre det på den gammeldagse måten (gjør det fra nettleseren din)

Redusere repetisjon

Selv uten å tenke på en løkke, kan vi fremdeles redusere repetisjon ved hjelp av variabler: basis-URL, , og basisfilnavnet endres aldri, så la oss tildele disse verdiene til variabler som kan brukes på nytt:

Påføring av for-loop

På dette punktet har vi forenklet mønsteret så langt at vi kan se hvor lite endringer med hver enkelt oppgave. Etter å ha lært om for -løkken, kan vi bruke den uten å tenke mye på (vi legger også til en søvnkommando slik at vi tar pause mellom nettforespørsler)

Genererer en liste

I de fleste situasjoner er det enkelt å lage en for-loop; det er opprettelsen av listen som kan være det harde arbeidet. Hva om vi ønsket å samle sidene for nummer 1 til 100? Det er mye å skrive.

Men hvis vi lar latskapen diktere vår tenkning, kan vi forestille oss at telling fra x til y virker som en iboende beregningsoppgave. Og det er det, og Unix har seq verktøyet for dette:

Genererer en liste over ikke-tall for iterasjon

Mange repeterende oppgaver er det ikke så enkelt som å telle fra x til y, og så blir problemet hvordan man genererer en ikke-lineær liste over varer? Dette er i utgangspunktet kunsten å samle inn data og administrere. Men la oss lage et enkelt scenario for oss selv:

For ti av de 10 bokstavene (eller flere) ordene som vises minst en gang i en overskrift på den nåværende NYTimes.com-forsiden, hent Wiktionary-siden for det ordet

Vi deler denne oppgaven i to deler:

  1. Hent en liste på ti 10 + -bokstavord fra nytimes.com-overskrifter
  2. Gi disse ordene til for-loop

Trinn 1: Bruk valpverktøyet (eller kommandolinje HTML-parser av ditt valg):

Trinn 2 (forutsatt at words -variabelen sendes videre):

Sjekk ut Softwa re Carpentry er utmerket guide til for-loops i Bash

Leave a Reply

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *