Gli script di shell sono ampiamente utilizzati nel mondo UNIX. Sono eccellenti per velocizzare le attività ripetitive e semplificare la complessa logica di esecuzione. Possono essere semplici come un insieme di comandi o possono orchestrare compiti complessi. In questo tutorial, impareremo di più sul linguaggio di scripting di Bash scrivendo uno script di esempio passo dopo passo.
Uno dei modi migliori per conoscere una nuova lingua è con l'esempio. Iniziamo con uno.
Il problema di Fizz-Buzz è molto semplice. È diventato famoso dopo che un programmatore, di nome Imran, l'ha usato come test di intervista. Risulta che il 90-99,5% dei candidati per un lavoro di programmazione non è semplicemente in grado di scrivere il programma più semplice. Imran ha preso questo semplice gioco Fizz-Buzz e ha chiesto ai candidati di risolverlo. Molti hanno seguito l'esempio di Imran e, oggi, è una delle domande più frequenti per un lavoro di programmazione. Se stai assumendo e hai bisogno di un modo per filtrare il 90% dei candidati, questo è un grosso problema da presentare.
Ecco le regole:
Questo è tutto ciò che c'è da fare. Sono sicuro che molti di voi possono già visualizzare i due o tre Se
dichiarazioni per risolvere questo. Lavoriamo attraverso questo usando il linguaggio di scripting di Bash.
Uno shebang si riferisce alla combinazione dei caratteri hash e del punto esclamativo: #!
. Il programma di caricamento del programma cercherà uno shebang sulla prima riga dello script e utilizzerà l'interprete specificato al suo interno. Uno shebang è costituito dalla seguente sintassi: #!interprete [parametri]
. L'interprete è il programma che viene utilizzato per interpretare la nostra lingua. Per lo scripting bash, sarebbe / Bin / bash
. Ad esempio, se si desidera creare uno script in PHP ed eseguirlo in console, probabilmente si vorrebbe usare / Usr / bin / php
(o il percorso dell'eseguibile PHP sulla tua macchina) come interprete.
#! / Usr / bin / phpSì, funzionerà davvero! Non è semplice? Assicurati di rendere il file eseguibile prima. Una volta fatto, questo script mostrerà le informazioni PHP come ti aspetteresti.
Mancia: Per assicurarti che lo script funzioni su quanti più sistemi possibili, puoi utilizzare
/ Bin / ENV
nello shebang. In quanto tale, invece di/ Bin / bash
, potresti usare/ bin / env bash
, che funzionerà su sistemi in cui l'eseguibile bash non è all'interno/bidone
.
Uscita di testo
L'output di uno script sarà uguale a, come ci si potrebbe aspettare, qualsiasi cosa venga emessa dal comando. Tuttavia, se vogliamo esplicitamente scrivere qualcosa sullo schermo, possiamo usarlo
eco
.#! / bin / bash echo "Hello World"L'esecuzione di questo script stamperà "Hello World" nella console.
csaba @ csaba ~ $ ./helloWorld.sh Ciao mondo csaba @ csaba ~ $
Presentazione delle variabili
Come con qualsiasi linguaggio di programmazione, quando si scrivono script di shell, è possibile utilizzare variabili.
#! / bin / bash message = "Ciao mondo" echo $ messaggioQuesto codice produce esattamente lo stesso messaggio "Hello World". Come puoi vedere, per assegnare un valore a una variabile, scrivi semplicemente il suo nome - escludi il simbolo del dollaro di fronte ad essa. Inoltre, fai attenzione agli spazi; non possono esserci spazi tra il nome della variabile e il segno di uguale. Così
messaggio = "Ciao"
invece dimessaggio = 'Ciao'
Quando desideri utilizzare una variabile, puoi prenderne il valore proprio come abbiamo fatto noi
eco
comando. Prepending a$
al nome della variabile restituirà il suo valore.Mancia: Il punto e virgola non è richiesto nello scripting bash. Puoi usarli nella maggior parte dei casi, ma fai attenzione: potrebbero avere un significato diverso da quello che ti aspetti.
Stampa dei numeri tra 1 e 100
Continuando con il nostro progetto dimostrativo, abbiamo bisogno di scorrere tutti i numeri compresi tra 1 e 100. Per questo, dovremo usare a
per
ciclo continuo.#! / bin / bash per il numero in 1 ... 100; fai eco $ numero fattoCi sono molte cose nuove che vale la pena notare in questo esempio - che, a proposito, stampa tutti i numeri da 1 a 100, un numero alla volta.
per
la sintassi in Bash è: per VARIABLE in RANGE; fare COMANDO fatto
.1 ... 100
in un intervallo nel nostro esempio. Sono utilizzati anche in altri contesti, che esamineremo a breve.fare
e per
sono in realtà due comandi separati. Se vuoi posizionare due comandi su una singola riga, dovrai separarli in qualche modo. Un modo è usare il punto e virgola. In alternativa è possibile scrivere il codice senza un punto e virgola spostandosi fare
alla seguente riga.#! / bin / bash per il numero in 1 ... 100 fai eco $ numero fatto
Ora che sappiamo come stampare tutti i numeri compresi tra 1 e 100, è tempo di prendere la nostra prima decisione.
#! / bin / bash per il numero in 1 ... 100; fai se [$ ((numero% 3)) -eq 0]; quindi echo "Fizz" echo $ number fi done
Questo esempio mostrerà "Fizz" per i numeri divisibili per 3. Di nuovo, dobbiamo fare i conti con un po 'di nuova sintassi. Prendiamoli uno per uno.
se ... poi ... altro ... fi
- questa è la sintassi classica per a Se
dichiarazione in Bash. Certo, il altro
parte è facoltativa, ma è necessaria per la nostra logica in questo caso.se COMMAND-RETURN-VALUE; poi…
- Se
verrà eseguito se il valore di ritorno del comando è zero. Sì, la logica in Bash è a base zero, il che significa che i comandi che vengono eseguiti correttamente escono con un codice di 0. Se qualcosa va storto, d'altra parte, verrà restituito un intero positivo. Per semplificare le cose: si considera qualsiasi cosa diversa da 0 falso
.$ ((Numero% 3))
restituirà il valore residuo della divisione della variabile, numero
, per 3. Si prega di notare che non abbiamo usato $
all'interno della parentesi - solo di fronte a loro.Ci si potrebbe chiedere dove sia il comando nel nostro esempio. Non c'è solo una parentesi con una strana espressione? Bene, si scopre che [
è in realtà un comando eseguibile. Per giocare con questo, prova i seguenti comandi nella tua console.
csaba @ csaba ~ $ che [/ usr / bin / [csaba @ csaba ~ $ [0 -eq 1] csaba @ csaba ~ $ echo $? 1 csaba @ csaba ~ $ [0 -eq 0] csaba @ csaba ~ $ echo $? 0
Mancia: Il valore di uscita di un comando viene sempre restituito nella variabile,
?
(punto interrogativo). Viene sovrascritto dopo l'esecuzione di ogni nuovo comando.
Stiamo andando bene finora. Abbiamo "Fizz"; ora facciamo la parte "Buzz".
#! / bin / bash per il numero in 1 ... 100; fai se [$ ((numero% 3)) -eq 0]; quindi echo "Fizz" elif [$ ((numero% 5)) -eq 0]; quindi echo "Buzz" altrimenti echo $ numero finito
Sopra, abbiamo introdotto un'altra condizione di divisibilità per 5: il Elif
dichiarazione. Questo, ovviamente, si traduce in altrimenti se, e verrà eseguito se il comando successivo lo restituisce vero
(o 0
). Come puoi osservare, le affermazioni condizionali all'interno []
vengono solitamente valutati con l'aiuto di parametri, come -eq
, che sta per "uguale".
Per la sintassi,
arg1 OP arg2
,OPERAZIONE
è uno di-eq
,-NE
,-lt
,-Le
,-gt
, o-ge
. Questi operatori aritmetici binari restituisconovero
Searg1
è uguale a, non uguale a, minore di, minore o uguale a, maggiore di, o maggiore di o uguale aarg2
, rispettivamente.arg1
earg2
possono essere numeri interi positivi o negativi. - Manuale di Bash
Quando si tenta di confrontare le stringhe, è possibile utilizzare il ben noto ==
segno, o anche un singolo segno di uguale farà. !=
ritorna vero
quando le stringhe sono diverse.
Finora, il codice viene eseguito, ma la logica non è corretta. Quando il numero è divisibile sia per 3 che per 5, la nostra logica farà eco solo a "Fizz". Modifichiamo il nostro codice per soddisfare l'ultima esigenza di FizzBuzz.
#! / bin / bash per il numero in 1 ... 100; fai se [$ ((numero% 3)) -eq 0]; quindi output = "Fizz" fi se [$ ((numero% 5)) -eq 0]; quindi output = "$ output Buzz" fi se [-z $ output]; quindi echo $ numero else echo $ output; fatto
Ancora una volta, abbiamo dovuto apportare una manciata di cambiamenti. Il più notevole è l'introduzione di una variabile, e quindi la concatenazione di "Buzz" ad esso, se necessario. Le stringhe in bash sono in genere definite tra virgolette doppie ("). Anche le virgolette singole sono utilizzabili, ma per semplificare la concatenazione, i doppi sono la scelta migliore. qualche testo $ variabile un altro testo
"sostituirà variabile $
con i suoi contenuti. Quando si desidera concatenare variabili con stringhe senza spazi tra di esse, è preferibile inserire il nome della variabile tra parentesi graffe. Nella maggior parte dei casi, come PHP, non sei obbligato a farlo, ma aiuta molto quando si tratta della leggibilità del codice.
Mancia: Non è possibile confrontare stringhe vuote. Ciò restituirebbe un parametro mancante.
Perché argomenti dentro []
sono trattati come parametri, per "["
, devono essere diversi da una stringa vuota. Quindi questa espressione, anche se logica, produrrà un errore: [$ output! = ""]
. Ecco perché l'abbiamo usato [-z $ output]
, che ritorna vero
se la stringa ha una lunghezza pari a zero.
Un modo per migliorare il nostro esempio è estrarre in funzioni l'espressione matematica dal Se
dichiarazioni, in questo modo:
#! / bin / bash function isDivisibleBy return $ (($ 1% $ 2) per il numero in 1 ... 100; fare se isDivisibleBy $ numero 3; quindi output = "Fizz" fi se isDivisibleBy $ numero 5; quindi output = "$ output Buzz" fi se [-z $ output]; quindi echo $ numero else echo $ output; fatto
Abbiamo preso le espressioni confrontando il resto con zero e le abbiamo spostate in una funzione. Ancor di più, abbiamo eliminato il confronto con zero, perché zero significa vero per noi. Dobbiamo solo restituire il valore dall'espressione matematica - molto semplice!
Mancia: La definizione di una funzione deve precedere la sua chiamata.
In Bash, puoi definire un metodo come function func_name commands;
. Facoltativamente, esiste una seconda sintassi per la dichiarazione delle funzioni: func_name () comandi;
. Quindi, possiamo rilasciare la stringa, funzione
e aggiungi "()"
dopo il suo nome. Personalmente preferisco questa opzione, come esemplificato nell'esempio sopra. È più esplicito e ricorda i linguaggi di programmazione tradizionali.
Non è necessario specificare i parametri per una funzione in Bash. L'invio di parametri a una funzione viene eseguito semplicemente enumerandoli su di essi dopo la chiamata di funzione separata da spazi bianchi. Non mettere virgole o parentesi nella chiamata di funzione - non funzionerà.
I parametri ricevuti vengono assegnati automaticamente alle variabili in base al numero. Il primo parametro va a $ 1
, il secondo a $ 2
, e così via. La variabile speciale, $ 0
fa riferimento al nome del file dello script corrente.
#! / bin / bash function exampleFunc echo $ 1 echo $ 0 IFS = "X" echo "$ @" echo "$ *" esempioFunc "uno" "due" "tre"
Questo codice produrrà il seguente risultato:
csaba @ csaba ~ $ ./parametersExamples.sh one ./parametersExamples.sh one two thre oneXtwoXthre
Analizziamo la fonte, riga per riga.
$ @
. Rappresenta tutti i parametri come una singola parola, esattamente come specificato nella chiamata di funzione.$ *
. Rappresenta tutti i parametri, presi uno a uno e concatenati con la prima lettera della variabile IFS. Ecco perché il risultato è oneXtwoXthre
.Come ho notato in precedenza, le funzioni in Bash possono restituire solo interi. Come tale, scrivere ritorna "una stringa"
sarebbe un codice non valido Tuttavia, in molte situazioni, è necessario più di uno zero o uno. Possiamo refactoring il nostro esempio di FizzBuzz in modo che, nel per
dichiarazione, faremo solo una chiamata di funzione.
#! / bin / bash function isDivisibleBy return $ (($ 1% $ 2)) function fizzOrBuzz if isDivisibleBy $ 1 3; quindi output = "Fizz" fi se isDivisibleBy $ 1 5; quindi output = "$ output Buzz" fi se [-z $ output]; quindi echo $ 1 else echo $ output; fi per il numero in 1 ... 100; fai il numero $ fizzOrBuzz fatto
Bene, questo è il primo passo. Abbiamo appena estratto tutto il codice in una funzione, chiamato fizzOrBuzz
, e quindi sostituito numero di $
con $ 1
. Tuttavia, tutto l'output si verifica in fizzOrBuzz
funzione. Vogliamo uscire dal per
loop con un eco
dichiarazione, in modo che possiamo anteporre ogni riga con un'altra stringa. Dobbiamo catturare il fizzOrBuzz
uscita della funzione.
# [...] per il numero in 1 ... 100; do echo "-'fizzOrBuzz $ numero '" fizzBuzzer = $ (numero $ fizzOrBuzz) echo "- $ fizzBuzzer" fatto
Abbiamo aggiornato il nostro per
loop solo un po '(nessun altro cambiamento). Ora abbiamo fatto eco a tutto due volte in due modi diversi per esemplificare le differenze tra le due soluzioni per lo stesso problema.
La prima soluzione per acquisire l'output di una funzione o un altro comando consiste nell'usare i backtick. Nel 99% dei casi, funzionerà perfettamente. Puoi semplicemente fare riferimento a una variabile nei backtick con il loro nome, come abbiamo fatto con numero di $
. Le prime poche righe dell'output dovrebbero ora apparire come:
csaba @ csaba ~ / Personal / Programming / NetTuts / Nozioni di base di scripting / Sorgenti BASH $ ./fizzBuzz.sh -1 -1 -2 -2 -Fizz -Fizz -4 -4 -Buzz -Buzz -Fizz -Fizz -7 -7
Come puoi vedere, tutto è duplicato. Stesso risultato.
Per la seconda soluzione, abbiamo scelto di assegnare prima il valore restituito a una variabile. In quel compito, abbiamo usato $ ()
, che, in questo caso, forchetta lo script, esegue il codice e restituisce l'output.
Ti ricordi che abbiamo usato il punto e virgola qua e là? Possono essere utilizzati per eseguire diversi comandi scritti sulla stessa riga. Se li separi con il punto e virgola, verranno semplicemente eseguiti.
Un caso più sofisticato è da usare &&
tra due comandi. Sì, questo è un AND logico; significa che il secondo comando verrà eseguito solo se ritorna il primo vero
(esce con 0). Questo è utile; possiamo semplificare il Se
dichiarazioni in questi stenografi:
#! / bin / bash function isDivisibleBy return $ (($ 1 $ $ 2)) function fizzOrBuzz isDivisibleBy $ 1 3 && output = "Fizz" isDivisibleBy $ 1 5 && output = "$ output Buzz" se [-z $ output ]; quindi echo $ 1 else echo $ output; fi per il numero in 1 ... 100; do echo "-'fizzOrBuzz $ numero '" fatto
Come nostra funzione, isDivisibleBy
restituisce un valore di ritorno appropriato, possiamo quindi utilizzare &&
per impostare la variabile che vogliamo. Cosa c'è dopo &&
sarà eseguito solo se la condizione è vero
. Allo stesso modo, possiamo usare ||
(carattere a doppia pipa) come OR logico. Ecco un rapido esempio qui sotto.
csaba @ csaba ~ $ echo "bubu" || echo "bibi" bubu csaba @ csaba ~ $ echo false || echo "bibi" false csaba @ csaba ~ $
Così lo fa per questo tutorial! Spero che tu abbia raccolto una manciata di nuovi suggerimenti e tecniche per scrivere i tuoi script di Bash. Grazie per la lettura e restate sintonizzati per articoli più avanzati su questo argomento.