Cum să buclați, de asemenea, proiectarea unui program pentru a face lucrări repetitive pentru dvs.
Bucla este una dintre cele mai fundamentale și puternice construcții în calcul, deoarece ne permite să repetăm un set de comenzi, de câte ori dorim, pe o listă de articole la alegere. O mare parte din gândirea calculațională presupune preluarea unei sarcini și rezolvarea ei într-un mod care poate fi aplicat în mod repetat la toate celelalte sarcini similare, iar bucla for este modul în care îl facem pe computer să facă acea muncă repetitivă:
Spre deosebire de majoritatea codului pe care l-am scris până acum la promptul interactiv, o buclă for nu se execută de îndată ce apăsăm Enter:
Putem scrie câte comenzi dorim în blocul dintre cuvintele cheie do
și done
:
Numai până când ajungem la done
și apăsăm Enter, bucla for își face treaba.
Aceasta este fundamental diferită de comanda și răspunsul linie cu linie pe care le-am experimentat până acum la prompt. Și prezice modul în care vom programa mai departe: mai puțin accent pe executarea comenzilor cu fiecare linie și mai mult accent pe planificarea funcționalității unui program și apoi executarea acestuia mai târziu.
Sintaxa de bază
Sintaxa pentru buclele for
poate fi confuză, așa că iată câteva exemple de bază pentru a pregăti / reîmprospăta înțelegerea lor:
Aici „o versiune mai elaborată folosind variabile:
O înlocuire a comenzii poate fi utilizată pentru a genera elementele pe care for
le repetă:
Dacă trebuie să citiți o listă de linii dintr-un și sunteți absolut siguri că niciuna dintre linii nu conține un spațiu în interiorul lor:
O buclă read-while este o variație a celor de mai sus, dar este mai sigur pentru citirea liniilor dintr-un fișier:
Construirea unei bucle de bază pentru
Să începem de la un început, cu un for
buclă minimă, apoi a construit-o în ceva mai elaborat, pentru a ne ajuta să înțelegem scopul lor.
Cea mai simplă buclă
Este cam la fel de simplu așa cum poți face o buclă for:
Ti s-a părut destul de lipsit de valoare? Da ar fi trebuit. Am scris patru linii de cod pentru a face ceea ce este necesar pentru a face o singură linie, echo "Hi"
.
Mai multe elemente din colecție
„Este greu de spus, dar s-a executat o” buclă „. S-a executat doar o dată. OK, deci cum o facem să se execute de mai multe ori? Adăugăm mai multe elemente (separate prin spațiu) în dreapta . Să adăugăm încă patru 1
„s:
OK, nu foarte interesant, dar programul părea cu siguranță cel puțin buclă: patru 1
„au dus la executarea a patru comenzi echo
.
Ce se întâmplă când înlocuim acele patru 1
„cu numere diferite? Și poate câteva cuvinte?
Și … nimic. Deci, bucla nu face automat nimic specific colecției de valori pe care i le-am dat. Oricum nu încă.
Consultați variabila de buclă
Să privim „în stânga cuvântului cheie in
și la acel x
. Ce rost are x
? O minusculă x
nu este numele unui cuvânt cheie sau comandă pe care l-am întâlnit până acum (și executarea acestuia la prompt va genera o eroare). Deci poate este o variabilă? Să încercăm să o referim în declarația echo
:
Bingo. Aceasta este cam funcționarea fundamentală a unei bucle for
: – Obțineți o colecție de articole / valori (Q Zebra 999 Smithsonian
) – Treceți-le într-o for
construct buclă- Utilizând variabila buclă (x
) ca substituent, scrieți comenzi între do
/ done
bloc.- Când bucla se execută, variabila buclei, x
, ia valoarea fiecăruia dintre elementele din lista – Q
, Zebra
, 999
, Smithsonian
, – și blocul de comenzi dintre do
și done
este apoi executat. Această secvență se repetă o dată pentru fiecare element din listă.
Blocul do
/ done
poate conține orice secvență de comenzi, chiar și un alt for
-loop:
Bucle-în-bucle este o construcție obișnuită în programare.În cea mai mare parte, voi încerca să evit atribuirea problemelor care ar implica acest tip de logică, deoarece poate fi dificil să se desfacă în timpul depanării.
Citiți un fișier, linie cu linie, fiabil cu read-while
Deoarece cat
tipărește un fișier linie cu linie, următorul lucru pentru buclă pare sensibil:
Cu toate acestea, substituirea comenzii va face ca cat
să împartă cuvintele după spațiu. Dacă list-of-dirs.txt
conține următoarele:
Ieșirea buclei for
va fi următoarea:
O buclă read-while va păstra cuvintele dintr-o linie:
De asemenea, putem rezulta din rezultat unei comenzi prin încadrarea ei în <(
și )
:
Țevi și bucle
Dacă proveniți din alte limbi, fluxurile de date vă pot fi necunoscute . Cel puțin sunt pentru mine, deoarece sintaxa pentru a lucra cu ei este mult mai directă și mai simplă în Bash decât în Ruby sau Python.
Cu toate acestea, dacă sunteți nou în programarea în orice limbaj, ce ar putea De asemenea, nu este clar cum este diferit lucrul cu fluxurile de date decât lucrul cu buclele.
De exemplu, următorul fragment:
– produce aceeași ieșire ca această buclă:
Și în funcție de modelul mental de lucruri, se pare că în ambele exemple, fiecare cuvânt, de ex. hello
, world
, este trecut printr-un proces de traducere (prin tr
) și apoi răsunat.
Țevi și filtre
Fără a intra în elementele fundamentale ale sistemului Unix, în care o conductă funcționează fundamental diferită de o buclă aici, permiteți-mi să sugerez o soluție mentală:
Programele care conduc de la stdin și stdout pot fi, de obicei, aranjate ca filtre, în care un flux de date intră într-un program și apare într-un format diferit:
Pentru activități care nu sunt doar transformarea datelor, de la filtru la filtru, gândiți-vă la utilizarea unei bucle. Ce ar putea fi, de exemplu, o sarcină? Având o listă de adrese URL, descărcați fiecare și trimiteți prin e-mail datele descărcate, cu un corp și un subiect personalizat:
Sursa de introducere a datelor, fiecare adresă URL din urls.txt
, nu este într-adevăr filtrat aici. În schimb, se face o sarcină în mai mulți pași pentru fiecare adresă URL.
Conducerea în read-while
Acestea fiind spuse, o buclă în sine poate fi implementată ca doar un alt filtru între filtre. Luați această variație a buclei read-while, în care rezultatul echo | grep
este introdus, linie cu linie, în while
buclă, care se tipărește pe stdout utilizând echo
, care este redirecționat către fișierul denumit some.txt:
Aceasta nu este o construcție pe care ar trebui să o faceți des, dacă este deloc, dar sperăm că întărește utilizarea conductelor în Unix.
Programare mai puțin interactivă
utilizarea frecventă a for
buclelor și a unor construcții similare înseamnă că „trecem peste zilele bune” de tastare într-o linie de c comenzi și executarea acestuia imediat după ce apăsăm Enter. Indiferent câte comenzi am împacheta într-o buclă for
, nu se întâmplă nimic până nu apăsăm done
cuvânt cheie.
Scrie o dată. Apoi buclați-l
Cu acea pierdere a interacțiunii linie cu linie cu shell-ul, pierdem principalul avantaj al promptului interactiv: feedback imediat. Și mai avem toate dezavantajele: dacă facem o greșeală de scriere mai devreme în blocul de comenzi dintre do
și done
, trebuie să începem peste tot.
Deci, iată cum putem atenua acest lucru:
Testați-vă codul, câte un caz la rând
Una dintre cele mai mari greșeli pe care le fac novicii cu Buclele for
cred că o buclă for
își rezolvă imediat problema. Deci, dacă ceea ce trebuie să facă este să descarce 10.000 de adrese URL, dar nu pot descărca corect o singură adresă URL, cred că punerea comenzilor lor defecte într-o buclă for
este un pas în direcția corectă.
În afară de aceasta, este o neînțelegerea unei bucle for
, problema practică este că acum rulați codul defect de 10.000 de ori, ceea ce înseamnă că trebuie să așteptați 10.000 de ori mai mult pentru a afla dacă codul dvs. este, vai, încă rupt.
Așa că pretinde că „nu ai auzit niciodată de for
bucle. Pretindeți-vă că trebuie să descărcați toate cele 10.000 de adrese URL, câte o comandă o dată. Puteți scrie comanda pentru ao face pentru prima adresă URL. Ce zici de al doilea? Odată ce aveți încredere rezonabilă că nu există erori minore de sintaxă, nu este timpul să vă gândiți cum să găsiți un model general pentru celelalte 9.997 de adrese URL.
Scrieți scripturi
Linia de comandă interactivă este excelentă.A fost distractiv să începi și va fi distractiv pe tot parcursul carierei tale de informatică. Dar când ai o sarcină mare în față, care implică mai mult de zece linii de cod, atunci este timpul să introduci codul într-un script shell. Nu vă încredeți în degetele umane eronate pentru a tasta din nou codul perfect.
Utilizați nano pentru a lucra pe bucle și pentru a le salva ca shell scripturi. Pentru fișiere mai lungi, voi lucra pe editorul de text al computerului meu (Text sublim) și apoi îl voi încărca pe server.
Exercițiu cu web scraping
Doar pentru a sintaxa și funcționarea buclei pentru, aici este procesul de gândire de la transformarea unei sarcini de rutină într-o buclă:
Pentru numerele de la 1 la 10, utilizați curl pentru a descărca intrarea Wikipedia pentru fiecare număr și salvați-o într-un fișier numit „
wiki-number-(whatever the number is).html
”
Modul vechi
Cu doar 10 adrese URL, am putea seta câteva variabile și apoi să copiem și să lipim comanda a curl, de 10 ori, făcând modificări la fiecare linie:
Și ghici ce? Functioneaza. Pentru 10 adrese URL, nu este o soluție proastă și este semnificativ mai rapid decât să o faci la vechiul mod (în browser-ul tău web)
Reducerea repetării
Chiar și fără să ne gândim la o buclă, putem reduce repetarea folosind variabile: adresa URL de bază, și numele fișierului de bază nu se schimbă niciodată, așa că să atribuim aceste valori variabilelor care poate fi reutilizat:
Aplicarea buclei for
În acest moment, am simplificat modelul până acum, încât să putem vedea cât de puțin se schimbă cu fiecare sarcină separată. După ce aflăm despre for
-loop, îl putem aplica fără să ne gândim prea mult (adăugăm și o comandă de repaus pentru a face o pauză între cererile web)
Generarea unui list
În majoritatea situațiilor, crearea unei bucle for este ușoară; este „crearea listei care poate fi o muncă grea. Ce se întâmplă dacă am dori să colectăm paginile pentru numerele de la 1 la 100? Asta” este o mulțime de tastare.
Dar dacă lăsăm lenea noastră să dicteze gândirea noastră, ne putem imagina că numărarea de la x la y pare o sarcină de calcul inerent. Și este, și Unix are utilitarul seq
pentru acest lucru:
Generarea unei liste de non-numere pentru iterație
Multe sarcini repetitive nu sunt la fel de simple ca numărarea de la x la y, astfel încât problema devine cum se generează o listă neliniară de articole? Aceasta este practic ceea ce arta colectării și gestionării datelor. Dar să facem un scenariu simplu pentru noi înșine:
Pentru zece cuvinte din 10 litere (sau mai multe) care apar cel puțin o dată într-un titlu pe prima pagină actuală NYTimes.com, preluați pagina Wiktionary pentru cuvântul respectiv
Împărțim această sarcină în două părți:
- Obțineți o listă de zece 10 + -Cuvinte de la titlurile nytimes.com
- Treceți aceste cuvinte la bucla noastră pentru forțe
Pasul 1: Folosind utilitarul pup (sau analizorul HTML din linia de comandă a alegerea dvs.):
Pasul 2 (presupunând că variabila words
este transmisă):
Verificați Softwa re Ghidul excelent pentru tâmplărie pentru bucle în Bash