Cicli For e Read-While in Bash

Come eseguire il loop, ovvero progettare un programma per eseguire un lavoro ripetitivo per te

Il ciclo è uno dei costrutti più fondamentali e potenti nell’informatica, perché ci permette di ripetere una serie di comandi, tutte le volte che vogliamo, su un elenco di elementi di nostra scelta. Gran parte del pensiero computazionale implica prendere un compito e risolverlo in un modo che possa essere applicato ripetutamente a tutti gli altri compiti simili, e il ciclo for è il modo in cui facciamo eseguire al computer quel lavoro ripetitivo:

A differenza della maggior parte del codice che abbiamo scritto finora al prompt interattivo, un ciclo for non viene eseguito non appena premiamo Invio:

Possiamo scrivere quanti comandi desideriamo nel blocco tra le parole chiave do e done :

Solo fino a quando non raggiungiamo done e premiamo Invio, il ciclo for fa il suo lavoro.

Questo è fondamentalmente diverso dal comando e risposta riga per riga che abbiamo sperimentato finora al prompt. E presagisce come programmeremo più avanti: meno enfasi sull’esecuzione di comandi con ogni riga e maggiore enfasi sulla pianificazione della funzionalità di un programma e quindi sulla sua esecuzione in un secondo momento.

Sintassi di base

La sintassi per i cicli for può creare confusione, quindi ecco alcuni esempi di base per preparare / aggiornare la tua comprensione di essi:

Ecco “una versione più elaborata che utilizza variabili:

Una sostituzione di comando può essere utilizzata per generare gli elementi su cui for itera in ciclo:

Se è necessario leggere un elenco di righe da un e sono assolutamente sicuri che nessuna delle righe contenga uno spazio al suo interno:

Un ciclo di lettura è una variazione del precedente, ma è più sicuro per leggere le righe da un file:

Costruire un ciclo for di base

Partiamo da un inizio, con un minimo for loop, e poi lo ha incorporato in qualcosa di più elaborato, per aiutarci a capire il loro scopo.

Il loop più semplice

Questo è altrettanto semplice come puoi creare un ciclo for:

Ti è sembrato abbastanza inutile? Sì, dovrebbe avere. Ho scritto quattro righe di codice per fare ciò che serve una singola riga, echo "Hi".

Più elementi nella raccolta

It “è difficile da dire, ma un” ciclo “è stato eseguito. È stato eseguito solo una volta. OK, quindi come possiamo farlo eseguire più di una volta? Aggiungi più elementi (separati da spazi) a destra di in. Aggiungiamo altre quattro 1 “s:

OK, non molto eccitante, ma il programma sembrava almeno eseguire un ciclo: quattro 1 “hanno portato all’esecuzione di quattro echo comandi.

Cosa succede quando sostituiamo quei quattro 1 “con numeri diversi? E forse un paio di parole?

E … niente. Quindi il ciclo non fa automaticamente nulla di specifico per la raccolta di valori che gli abbiamo dato. Non ancora, comunque.

Fare riferimento alla variabile loop

Guardiamo a sinistra della parola chiave in e x. Qual è lo scopo di questo x? Un x minuscolo non è “il nome di una parola chiave o di un comando che abbiamo incontrato finora (ed eseguirlo da solo al prompt genererà un errore). Quindi forse è una variabile? Proviamo a farvi riferimento nell’istruzione echo:

Bingo. Questo è praticamente il funzionamento fondamentale di un ciclo for: – Ottieni una raccolta di elementi / valori (Q Zebra 999 Smithsonian) – Passali in un for costrutto del ciclo – Utilizzando la variabile del ciclo (x) come segnaposto, scrivi i comandi tra do / done blocco. – Quando il ciclo viene eseguito, la variabile del ciclo, x, prende il valore di ciascuno degli elementi in l’elenco – Q, Zebra, 999, Smithsonian, – e il blocco di comandi tra do e done viene quindi eseguito. Questa sequenza si ripete una volta per ogni elemento nell’elenco.

Il blocco do / done può contenere qualsiasi sequenza di comandi, anche un altro for -loop:

Loops-within-loop è un costrutto comune nella programmazione.Per la maggior parte, cercherò di evitare di assegnare problemi che implicherebbero questo tipo di logica, poiché può essere difficile sciogliere le torsioni durante il debug.

Leggere un file riga per riga, affidabile con read-while

Poiché cat stampa un file riga per riga, il seguente ciclo for sembra sensato:

Tuttavia, la sostituzione del comando farà sì che cat divida le parole per spazio. Se list-of-dirs.txt contiene il seguente:

L’output del for loop sarà questo:

Un ciclo di lettura mentre conserverà le parole all’interno di una riga:

Possiamo anche eseguire il pipe dal risultato di un comando racchiudendolo tra <( e ):

Pipes and loop

Se provieni da altre lingue, i flussi di dati potrebbero non esserti familiari . Almeno lo sono per me, poiché la sintassi per lavorare con loro è molto più diretta e diretta in Bash che in Ruby o Python.

Tuttavia, se sei nuovo nella programmazione in qualsiasi linguaggio, cosa potrebbe inoltre non è chiaro come lavorare con i flussi di dati sia diverso dal lavorare con i loop.

Ad esempio, il seguente snippet:

– produce lo stesso output di questo ciclo:

E a seconda del tuo modello mentale delle cose, sembra che in entrambi gli esempi, ogni parola, ad esempio hello, world, viene passato attraverso un processo di traduzione (tramite tr) e quindi ripetuto.

Pipes e filtri

Senza entrare nei fondamenti del sistema Unix, in cui un pipe opera in modo fondamentalmente diverso da un loop qui, lasciatemi suggerire una soluzione mentale:

I programmi che eseguono il pipe da stdin e stdout possono generalmente essere organizzati come filtri, in cui un flusso di dati entra in un programma e ne esce in un formato diverso:

Per attività che sono più della semplice trasformazione dei dati, da filtro a filtro, pensa all’utilizzo di un ciclo. Quale potrebbe essere un compito? Dato un elenco di URL, scarica ciascuno e invia tramite email i dati scaricati, con un corpo e un oggetto personalizzati:

La sorgente di input dei dati, ogni URL in urls.txt, non viene realmente filtrato qui. Invece, viene eseguita un’attività in più passaggi per ogni URL.

Piping in read-while

Detto questo, è possibile implementare un ciclo stesso come un solo filtro in più tra i filtri. Prendi questa variante del ciclo di lettura durante, in cui il risultato di echo | grep viene convogliato, riga per riga, nel while loop, che stampa su stdout utilizzando echo, che viene reindirizzato al file denominato some.txt:

Questo non è un costrutto che potresti dover fare spesso, se non del tutto, ma si spera che rafforzi l’uso delle pipe in Unix.

Programmazione meno interattiva

Il l’uso frequente di for cicli e costrutti simili, significa che stiamo “superando i bei vecchi” giorni di digitazione in una riga di c ommands e farlo eseguire subito dopo aver premuto Invio. Non importa quanti comandi inseriamo in un for ciclo, non accade nulla finché non premiamo la parola chiave done.

Scrivi una volta. Quindi loop it

Con quella perdita di interazione riga per riga con la shell, perdiamo il vantaggio principale del prompt interattivo: feedback immediato. E abbiamo ancora tutti gli svantaggi: se facciamo un errore di battitura in precedenza nel blocco dei comandi tra do e done, dobbiamo iniziare dappertutto.

Ecco come mitigarlo:

Testa il tuo codice, un caso alla volta

Uno dei più grandi errori commessi dai principianti for loop è che pensano che un for loop risolva immediatamente il loro problema. Quindi, se quello che devono fare è scaricare 10.000 URL, ma non possono scaricare correttamente un solo URL, pensano che inserire i loro comandi difettosi in un ciclo for sia un passo nella giusta direzione.

Oltre a questo, è fondamentalmente malinteso di un for loop, il problema pratico è che ora stai eseguendo il tuo codice non funzionante 10.000 volte, il che significa che devi aspettare 10.000 volte più a lungo per scoprire che il tuo codice è, ahimè, ancora rotto.

Quindi fingi di “non aver mai sentito parlare di for loop. Immagina di dover scaricare tutti i 10.000 URL, un comando alla volta. Puoi scrivere il comando per farlo per il primo URL. E il secondo? Una volta che sei ragionevolmente sicuro che nessun piccolo errore di sintassi ti stia inciampando, allora è il momento di pensare a come trovare un pattern generale per gli altri 9.997 URL.

Scrivi script

La riga di comando interattiva è fantastica.È stato divertente iniziare e lo sarà per tutta la tua carriera informatica. Ma quando hai un grosso compito davanti a te, che coinvolge più di dieci righe di codice, allora è il momento di inserire quel codice in un script di shell. Non fidarti delle tue fallibili dita umane per ridigitare perfettamente il codice.

Usa nano per lavorare sui loop e salvarli come shell script. Per file più lunghi, lavorerò sull’editor di testo del mio computer (Sublime Text) e poi caricherò sul server.

Esercizio con il web scraping

Solo per mettere a terra il sintassi e funzionamento del ciclo for, ecco il processo mentale che trasforma un’attività di routine in un ciclo:

Per i numeri da 1 a 10, usa curl per scaricare la voce di Wikipedia per ogni numero e salvala in un file denominato “wiki-number-(whatever the number is).html

Alla vecchia maniera

Con solo 10 URL, potremmo impostare un paio di variabili e quindi copiare e incollare il comando a curl, 10 volte, apportando modifiche a ciascuna riga:

E indovina cosa? Funziona. Per 10 URL, non è una cattiva soluzione ed è significativamente più veloce che farlo alla vecchia maniera (farlo dal tuo browser web)

Ridurre la ripetizione

Anche senza pensare a un ciclo, possiamo comunque ridurre la ripetizione utilizzando le variabili: l’URL di base, , e il nome del file di base non cambiano mai, quindi assegniamo questi valori alle variabili che può essere riutilizzato:

Applicare il ciclo for

A questo punto, abbiamo semplificato il modello fino ad ora che possiamo vedere quanto poco cambia con ogni attività separata. Dopo aver appreso del for -loop, possiamo applicarlo senza pensarci troppo (aggiungiamo anche un comando sleep in modo da fare una pausa tra le richieste web)

Generazione di un list

Nella maggior parte delle situazioni, creare un ciclo for è facile; è la creazione dell’elenco che può essere il duro lavoro. E se volessimo raccogliere le pagine per i numeri da 1 a 100? È un sacco di digitazione.

Ma se lasciamo che sia la nostra pigrizia a dettare il nostro pensiero, possiamo immaginare che il conteggio da x a y sembri un compito intrinsecamente computazionale. E lo è, e Unix ha l’utilità seq per questo:

Generazione di un elenco di non numeri per l’iterazione

Molte attività ripetitive non è semplice come contare da x a y, quindi il problema diventa come generare un elenco non lineare di elementi? Questo è fondamentalmente ciò che è l’arte della raccolta e della gestione dei dati. Ma creiamo uno scenario semplice per noi stessi:

Per dieci delle parole di 10 lettere (o più) che compaiono almeno una volta in un titolo sulla prima pagina corrente di NYTimes.com, recupera la pagina Wikizionario per quella parola

Suddividiamo questo compito in due parti:

  1. Recupera una lista di dieci 10 + -lettera parole dai titoli di nytimes.com
  2. Passa quelle parole al nostro ciclo for

Passaggio 1: utilizzo dell’utilità pup (o parser HTML della riga di comando di la tua scelta):

Passaggio 2 (supponendo che la variabile words venga trasmessa):

Dai un’occhiata a Softwa L’eccellente guida di re Carpentry ai cicli for in Bash

Leave a Reply

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *