GNU/Linux >> Linux Esercitazione >  >> Linux

Come scrivere un ciclo in Bash

Un motivo comune per cui le persone vogliono imparare la shell Unix è sbloccare la potenza dell'elaborazione batch. Se vuoi eseguire una serie di azioni su molti file, uno dei modi per farlo è costruire un comando che esegua un'iterazione su quei file. Nella terminologia di programmazione, questo è chiamato controllo di esecuzione, e uno degli esempi più comuni è il for ciclo.

Un per loop è una ricetta che descrive in dettaglio quali azioni vuoi che il tuo computer esegua per ogni oggetto dati (come un file) specificato.

Il classico ciclo for

Il terminale Linux

  • I 7 migliori emulatori di terminale per Linux
  • 10 strumenti da riga di comando per l'analisi dei dati in Linux
  • Scarica ora:cheat sheet SSH
  • Cheat sheet sui comandi avanzati di Linux
  • Esercitazioni sulla riga di comando di Linux

Un ciclo facile da provare è quello che analizza una raccolta di file. Questo probabilmente non è un ciclo utile da solo, ma è un modo sicuro per dimostrare a te stesso che hai la capacità di gestire ogni file in una directory individualmente. Innanzitutto, crea un semplice ambiente di test creando una directory e inserendo alcune copie di alcuni file in essa. All'inizio qualsiasi file funzionerà, ma gli esempi successivi richiedono file grafici (come JPEG, PNG o simili). Puoi creare la cartella e copiarvi i file utilizzando un file manager o nel terminale:

$ mkdir example
        $ cp ~/Pictures/vacation/*.{png,jpg} example

Cambia la directory nella tua nuova cartella, quindi elenca i file in essa contenuti per confermare che il tuo ambiente di test è quello che ti aspetti:

$ cd example
$ ls -1
cat.jpg
design_maori.png
otago.jpg
waterfall.png

La sintassi per scorrere ogni file individualmente in un ciclo è:creare una variabile (f per file, per esempio). Quindi definisci il set di dati che vuoi che la variabile scorra. In questo caso, scorrere tutti i file nella directory corrente utilizzando * carattere jolly (il * il carattere jolly corrisponde a tutto ). Quindi termina questa clausola introduttiva con un punto e virgola (; ).

$ for f in * ;

A seconda delle tue preferenze, puoi scegliere di premere Invio qui. La shell non tenterà di eseguire il ciclo finché non sarà sintatticamente completo.

Quindi, definisci cosa vuoi che accada con ogni iterazione del ciclo. Per semplicità, usa il file comando per ottenere un po' di dati su ciascun file, rappresentato dalla f variabile (ma preceduta da $ per dire alla shell di sostituire il valore della variabile con qualunque cosa la variabile contenga attualmente):

do file $f ;

Termina la clausola con un altro punto e virgola e chiudi il ciclo:

done

Premi Invio per avviare la shell a pedalare tutto nella directory corrente. Il per loop assegna ogni file, uno per uno, alla variabile f ed esegue il tuo comando:

$ for f in * ; do
        > file $f ;
        > done
        cat.jpg: JPEG image data, EXIF standard 2.2
        design_maori.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced
        otago.jpg: JPEG image data, EXIF standard 2.2
        waterfall.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced

Puoi anche scriverlo in questo modo:

$ for f in *; do file $f; done
        cat.jpg: JPEG image data, EXIF standard 2.2
        design_maori.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced
        otago.jpg: JPEG image data, EXIF standard 2.2
        waterfall.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced

Sia il formato multilinea che quello a linea singola sono gli stessi per la tua shell e producono esattamente gli stessi risultati.

Un esempio pratico

Ecco un esempio pratico di come un ciclo può essere utile per l'informatica di tutti i giorni. Supponi di avere una raccolta di foto delle vacanze che desideri inviare agli amici. I tuoi file di foto sono enormi, il che li rende troppo grandi per essere inviati tramite e-mail e scomodi da caricare sul tuo servizio di condivisione foto. Vuoi creare versioni web più piccole delle tue foto, ma hai 100 foto e non vuoi perdere tempo a ridurre ogni foto, una per una.

Innanzitutto, installa ImageMagick comando utilizzando il tuo gestore di pacchetti su Linux, BSD o Mac. Ad esempio, su Fedora e RHEL:

$ sudo dnf install ImageMagick

Su Ubuntu o Debian:

$ sudo apt install ImageMagick

Su BSD, usa le porte o pkgsrc. Su Mac, usa Homebrew o MacPorts.

Una volta installato ImageMagick, hai una serie di nuovi comandi per operare sulle foto.

Crea una directory di destinazione per i file che stai per creare:

$ mkdir tmp

Per ridurre ogni foto al 33% delle sue dimensioni originali, prova questo ciclo:

$ for f in * ; do convert $f -scale 33% tmp/$f ; done

Quindi guarda nel tmp cartella per vedere le tue foto in scala.

Puoi utilizzare un numero qualsiasi di comandi all'interno di un ciclo, quindi se devi eseguire azioni complesse su un batch di file, puoi inserire l'intero flusso di lavoro tra do e fatto dichiarazioni di un per ciclo continuo. Ad esempio, supponi di voler copiare ogni foto elaborata direttamente in una directory di foto condivisa sul tuo host web e rimuovere il file di foto dal tuo sistema locale:

$ for f in * ; do 
    convert $f -scale 33% tmp/$f
    scp -i seth_web tmp/$f [email protected]:~/public_html
    trash tmp/$f ;
  done

Per ogni file elaborato da for loop, il tuo computer esegue automaticamente tre comandi. Ciò significa che se elabori solo 10 foto in questo modo, risparmi 30 comandi e probabilmente almeno altrettanti minuti.

Limitazione del ciclo

Un ciclo non deve sempre guardare tutti i file. Potresti voler elaborare solo i file JPEG nella tua directory di esempio:

$ for f in *.jpg ; do convert $f -scale 33% tmp/$f ; done
$ ls -m tmp
cat.jpg, otago.jpg

Oppure, invece di elaborare i file, potrebbe essere necessario ripetere un'azione un numero specifico di volte. Un per la variabile di loop è definita dai dati che gli fornisci, quindi puoi creare un loop che itera sui numeri anziché sui file:

$ for n in {0..4}; do echo $n ; done
0
1
2
3
4

Più loop

Ora ne sai abbastanza per creare i tuoi loop. Finché non ti senti a tuo agio con il loop, usali su copie dei file che si desidera elaborare e, il più spesso possibile, utilizzare comandi con protezioni integrate per evitare di intasare i dati e commettere errori irreparabili, come rinominare accidentalmente un'intera directory di file con lo stesso nome, sovrascrivendo ciascuno l'altro .

Per avanzato per ripeti gli argomenti, continua a leggere.

Non tutte le shell sono Bash

Il per la parola chiave è incorporata nella shell Bash. Molte shell simili utilizzano la stessa parola chiave e sintassi, ma alcune shell, come tcsh, utilizzano una parola chiave diversa, come foreach , invece.

In tcsh, la sintassi è simile nello spirito ma più rigorosa di Bash. Nell'esempio di codice seguente, non digitare la stringa foreach? nelle righe 2 e 3. È un messaggio secondario che ti avverte che stai ancora costruendo il tuo loop.

$ foreach f (*)
foreach? file $f
foreach? end
cat.jpg: JPEG image data, EXIF standard 2.2
design_maori.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced
otago.jpg: JPEG image data, EXIF standard 2.2
waterfall.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced

In tcsh, entrambi foreach e fine deve apparire da solo su righe separate, quindi non puoi creare un per loop su una riga come puoi con Bash e shell simili.

Per i loop con il comando trova

In teoria, potresti trovare una shell che non fornisce un for funzione loop, oppure potresti semplicemente preferire utilizzare un comando diverso con funzionalità aggiuntive.

Il trovare Il comando è un altro modo per implementare la funzionalità di un for loop, in quanto offre diversi modi per definire l'ambito di quali file includere nel ciclo e le opzioni per l'elaborazione parallela.

Il trovare comando ha lo scopo di aiutarti a trovare i file sui tuoi dischi rigidi. La sua sintassi è semplice:fornisci il percorso della posizione che desideri cercare e trova trova tutti i file e le directory:

$ find . 
.
./cat.jpg
./design_maori.png
./otago.jpg
./waterfall.png

Puoi filtrare i risultati della ricerca aggiungendo una parte del nome:

$ find . -name "*jpg"
./cat.jpg
./otago.jpg

Il bello di trova è che ogni file che trova può essere inserito in un ciclo usando -exec bandiera. Ad esempio, per ridurre solo le foto PNG nella directory di esempio:

$ find . -name "*png" -exec convert {} -scale 33% tmp/{} \;
$ ls -m tmp
design_maori.png, waterfall.png

In -exec clausola, i caratteri tra parentesi {} sostituire qualsiasi elemento trova sta elaborando (in altre parole, qualsiasi file che termina in PNG che è stato individuato, uno alla volta). Il -exec La clausola deve essere terminata con un punto e virgola, ma Bash di solito cerca di utilizzare il punto e virgola per se stesso. "Esci" dal punto e virgola con una barra rovesciata (\; ) in modo che trovi sa trattare quel punto e virgola come il suo carattere di terminazione.

Il trovare il comando è molto bravo in quello che fa e a volte può essere troppo bravo. Ad esempio, se lo riutilizzi per trovare file PNG per un altro processo fotografico, riceverai alcuni errori:

$ find . -name "*png" -exec convert {} -flip -flop tmp/{} \;    
convert: unable to open image `tmp/./tmp/design_maori.png':
No such file or directory @ error/blob.c/OpenBlob/2643.
...

Sembra che trova ha individuato tutti i file PNG, non solo quelli nella directory corrente (. ) ma anche quelli che hai elaborato in precedenza e inseriti nel tuo tmp sottodirectory. In alcuni casi, potresti voler trovare per cercare la directory corrente più tutte le altre directory al suo interno (e tutte le directory in quelle ). Può essere un potente strumento di elaborazione ricorsiva, specialmente in strutture di file complesse (come directory di artisti musicali contenenti directory di album piene di file musicali), ma puoi limitarlo con -maxdepth opzione.

Per trovare solo file PNG nella directory corrente (escluse le sottodirectory):

$ find . -maxdepth 1 -name "*png"

Per trovare ed elaborare i file nella directory corrente più un livello aggiuntivo di sottodirectory, aumenta la profondità massima di 1:

$ find . -maxdepth 2 -name "*png"

L'impostazione predefinita è di scendere in tutte le sottodirectory.

Looping per divertimento e profitto

Più usi i loop, più tempo e fatica risparmi e più grandi sono le attività che puoi affrontare. Sei solo un utente, ma con un ciclo ben congegnato, puoi fare in modo che il tuo computer faccia il duro lavoro.

Puoi e dovresti trattare il loop come qualsiasi altro comando, tenendolo a portata di mano quando devi ripetere una o due azioni singole su più file. Tuttavia, è anche un gateway legittimo per una programmazione seria, quindi se devi svolgere un'attività complessa su un numero qualsiasi di file, prenditi un momento della tua giornata per pianificare il tuo flusso di lavoro. Se riesci a raggiungere il tuo obiettivo su un file, allora avvolgi quel processo ripetibile in un for loop è relativamente semplice e l'unica "programmazione" richiesta è la comprensione di come funzionano le variabili e un'organizzazione sufficiente per separare i file non elaborati da quelli elaborati. Con un po' di pratica, puoi passare da un utente Linux a un utente Linux che sa come scrivere un loop, quindi esci e fai funzionare il tuo computer per te!


Linux
  1. Come usare i comandi della cronologia di Bash

  2. Come eseguire il debug di uno script Bash?

  3. Come fermare lo script Loop Bash nel terminale?

  4. Come rilevare Bash>=4.0?

  5. Come ottenere lo stato di uscita un ciclo in bash

Bash mentre Loop

Bash For Loop

Bash fino a Loop

Scripting Bash:come scrivere dati su file di testo

Script di shell per principianti - Come scrivere script Bash in Linux

Come eseguire uno script Bash