Home > Argomenti vari > ShElL

ShElL

5 Maggio 2007

La shell e’ il migliore alleato nell’uso di un sistema GNU/Linux! Se si sceglie di usare la linea di comando, avremo spesso a che fare con espressioni che coinvolgono l’uso della redirezione, delle pipe e della concatenazione dei comandi. Utilizzare la shell risulta piu’ rapido dell’utilizzare una qualsiasi interfaccia grafica, e si presenta percio’ indispensabile nell’uso produttivo di GNU/Linux. Quella che segue e’ una guida sintetica all’utilizzo della shell. La guida e’ stata suddivisa in tre parti per motivi di praticita’. Buona lettura.
——————–Programmazione con la Shell———————

————————-Sommario parte 1—————————
La shell Bash
I file di configurazione
Cenni sulle variabili
Cenni sui commenti
La variabile PATH
I prompts
Il file storico
Le variabili della posta
Varie
Gli alias
I permessi sui file

—————————La shell Bash——————————
Bash e’ un acronimo di Bourne Again SHell, si tratta di una shell compatibile con la shell Bourne, che e’ stata una delle shell piu’ usate in ambiente Unix alla quale aggiunge alcune migliorie mutuate anche dalle altre shell Unix. E’ in grado quindi di eseguire script scritti per la Bourne shell, mettendo a disposizione al contempo costrutti e comandi piu’ complessi non presenti nella Bourne shell originale. Non ultimo punto a suo favore consiste nel fatto di essere la shell predefinita di quasi la totalita’ delle distribuzioni Linux e di conseguenza la piu’ usata. Per chi non lo sapesse, la shell e’ un programma che agisce da intermediario tra l’utente e il kernel, in pratica si occupa di tradurre i comandi dell’utente e li passa al kernel per l’esecuzione. Il suo nome significa conchiglia perche’ appunto racchiude la sua perla, il kernel. Come quasi tutto il software scritto per il sistema operativo Linux e’ altamente configurabile.

———————I file di configurazione————————-
La shell puo’ usare cinque files di configurazione, ma spesso nelle varie distribuzioni non vengono usati tutti, d’altra parte vedremo che non e’ difficile crearsene di propri. I file sono:
/etc/profile
/etc/bashrc
~/.bash_profile
~/.bashrc
~/.bash_logout
Fondamentalmente possiamo dividerli in due gruppi: file globali e file locali, cioe’ quelli che contengono direttive di configurazione valide per tutti gli utenti, sono quelli che si trovano sotto la directory /etc, e quelli che contengono direttive di configurazione valide solo per l’utente che possiede la cartella nella directory /home che li contiene. Infatti nell’elenco sono preceduti da un carattere tilde (~ che nei sistemi Unix e’ un collegamento breve alla directory base dell’utente), e preceduti da un punto che li rende “invisibili” al comando ls senza l’argomento -a.
Se non dovessero essere presenti tutti nel sistema, non preoccupatevi, non tutti sono necessari, inoltre quelli necessari li creeremo in seguito.
Cominciamo a esaminarli uno ad uno:
/etc/profile
E’ il file di configurazione globale che determina le variabili di ambiente e i programmi da eseguire per ogni utente che manda in esecuzione la shell. Per fare un paragone con il mondo Dos potrebbe essere qualcosa di molto simile al file autoexec.bat.
/etc/bashrc
E’ un file di configurazione globale molto simile al precedente, per questo motivo spesso non e’ usato, contiene alias (collegamenti brevi a comandi molto lunghi li vedremo in seguito), e pezzi di codice nel linguaggio di scripting della shell che devono essere eseguiti alla partenza della shell. Tutto puo’ essere spostato senza problema nel file /etc/profile.
~/.bash_profile
E’ un file di configurazione locale che contiene direttive di configurazione e variabili di ambiente specifiche dell’utente al quale appartiene la directory /home in cui si trova. Il file viene letto ed eseguito successivamente a quelli globali e’ modifica o sovrascrive variabili che riguardano esclusivamente l’utente.
~/.bashrc
E’ un file di configurazione locale che contiene direttive di configurazione come gli alias, o funzioni definite dall’utente. Il file viene letto ed eseguito successivamente a quelli globali, gli alias o le funzioni saranno specifici dell’utente e non influenzeranno nessun altro utente. E’ il corrispondente locale di /etc/bashrc.
~/bash_logout
E’ un file di configurazione locale che contiene comandi da eseguire quando l’utente esce dalla shell. I comandi influenzano solo l’utente che possiede la cartella /home nella quale si trova.

———————Cenni sulle variabili————————–
Il metodo piu’ usato per archiviare temporeneamente uno o piu’ valori consiste nell’usare le variabili, cioe’ usare un’area di memoria del computer assegnandogli un nome a cui si possa far riferimento in seguito per recuperare il valore assegnato, si puo’ pensare a una variabile come una scatola chiamata per esempio mia_scatola, se noi mettiamo nella scatola una palla possiamo dire che il valore della variabile e’ rappresentato dall’elemento palla. Approfondiremo in seguito le variabili e il loro uso nello scrivere codice eseguibile dalla bash, per ora per la configurazione ci interessano solo due accezioni del termine cioe’ le variabili di ambiente (environmental) e le variabili locali (local). Le variabili di ambiente sono quelle variabili create autonomamente dal sistema operativo e normalmente sono definite nel file /etc/profile , come per esempio SHELL, PS1, PS2, ecc. saranno discusse piu’ avanti. Le variabili locali sono quelle variabili definite dall’utente e sono generalmente definite nel file ~/.bashrc che si trova come abbiamo visto nella /home dell’utente del quale possono influenzare l’ambiente. La definizione di una variabile avviene in un modo intuitivo e elementare. Consta di tre parti: il nome della variabile seguito dall’operatore di assegnamento “=” ,e il valore da assegnare, cioe’:nome_variabile=valore_variabile
Riutilizzando il paragone della scatola si potrebbe dire quindi che il valore della variabile mia_scatola=palla. Ponete attenzione al fatto che non ci sono spazi vuoti tra i componenti dell’assegnazione. Una volta definita la variabile la possiamo rendere disponibile ai programmi che l’utente usa con il comando export, cioe’:
export nome_variabile
Per accedere al valore di una variabile cioe’ per recuperarne il valore dobbiamo far precedere al nome variabile il suffisso “$”. Per esempio per conoscere il valore della variabile SHELL possiamo digitare il comando:
echo $SHELL che produrra’ una stampa a video /bin/bash
In parole povere il nome_variabile sara’ espanso nel valore_variabile quando il primo e’ preceduto dal simbolo “$”. Ritorneremo in seguito su come manipolare una variabile, ma fin da ora appare chiaro che comprenderlo e’ essenziale perche’ tutti i file di configurazione del sistema sono scritte nel linguaggio della shell Bash.

——————–Cenni sui commenti——————————-
Se mentre editi un file di configurazione ti trovi davanti a una linea di codice dagli effetti dubbi invece di cancellarla puoi commentarla. Commentare e’ l’azione di “rimuovere” una o piu’ linee dall’esecuzione dello script facendo precedere la linea da commentare dal carattere “#” senza cancellare. Chiaramente si puo’ usare il carattere “#” anche per inserire commenti che migliorino la leggibilita’ dello script, e che ci ricordino in seguito checosa abbiamo scritto.
Per esempio:
echo “sono un testo di prova”
#questo e’ un commento esplicativo
#qui sotto c’e’ un comando commentato che non verra’ eseguito
#echo “sono un testo che non verra’ visto”
La comodita’ del commento rispetto alla cancellazione e che la linea puo’ essere ripristinata immediatamente.

——————-La variabile PATH——————————–
La prima variabile da configurare e’ la variabile PATH che definisce le directory a cui possiamo accedere da qualsiasi punto del filesystem. Per esempio potremmo avere un programma nella directory /bin chiamato mio_prog, se la directory /bin e’ presente nella variabile PATH possiamo lanciare il programma da qualsiasi posizione nel filesystem, altrimenti saremmo costretti o a digitare l’intero percorso /bin/mio_prog oppure portarci nella directory digitando prima cd /bin e successivamente ./mio_prog. Il punto e la barra traversa (slash) che precedono il nome del programma dicono alla shell di cercare di eseguire quel file se ci sono i permessi adatti. La variabile PATH e’ definita in /etc/profile e ha una sintassi leggermente diversa dal normale, ogni percorso di directory alla destra dell’operatore di assegnazione “=” e separata dal carattere “:” ,esempio: PATH=/bin:/usr/bin:/usr/local/bin export PATH rendera’ possibile mandare in esecuzione da qualsiasi punto del filesystem tutti gli eseguibili che si trovano nelle cartelle dichiarate nella variabile PATH. Se noi volessimo aggiungere altri valori alla variabile PATH potremmo digitare semplicemente:
PATH=$PATH:/usr/games export PATH che aggiungera’ al valore gia’ esistente della variabile PATH il nostro nuovo valore, infatti il nome variabile preceduto dal simbolo “$” verra’ espanso con il contenuto originale della variabile cioe’ /bin:/usr/bin:/usr/local/bin che diventera’ /bin:/usr/bin:/usr/local/bin:/usr/games. Si puo’ modificare il proprio path inserendo il comando precedente in ~/.bash_profile.

———————–I prompts———————————–
Il prompt non e’ altro che il sistema in attesa di input dall’utente, la sua forma classica e’:
nome_utente@nome_computer:[#,$]
un prompt generico in questo momento poterbbe apparire come root@poldo:~#
e mi sta’ dicendo che sono l’utente “root” sulla macchina “poldo” e mi trovo nella mia home directory “~”, se fossi stato un semplice utente al posto del “#” ci sarebbe stato probabilmente un “$”. Dico probabilmente perche’ quello che vediamo riflette i valori della variabile PS1 definita nel file /etc/profile che e’ di proprieta’ dell’utente root, se noi volessimo un prompt diverso potremmo ridefinire la variabile PS1 nel file ~/.bash_profile. Questa variabile accetta dei valori predefiniti che sono ottenuti facendo seguire alla barra rovesciata (backslash) dei caratteri speciali che sono:
t l’ora corrente nel formato HH:MM:SS
d la data in formato esteso es. “Tue May 18″
n un carattere di nuova linea
s il nome della shell
w la directory corrente
W il percorso completo alla directory corrente
u il nome dell’utente
h il nome della macchina
# il numero del processo associato al comando in esecuzione
! la posizione numerica nel file storico dei comandi
$ se l’UID e’ 0 mostraun “#”, altrimenti ub “$”
Quindi inserendo opportunamente questi caratteri possiamo modificare l’aspetto del nostro prompt. Se assegno alla variabile PS1 i seguenti valori: PS1=”[u@h W]$” il mio prompt mi apparira’ cosi’:
[root@poldo /root]#
se modifico la variable cosi’: PS1=”[t s]$ ”
il mio prompt mi apparira’ cosi’:
[12:18:24 bash]#
Oltre a questi caratteri speciali la variabile PS1 puo’ contenere anche comandi per esempio se volessi far apparire la versione del kernel:
PS1=”`uname -r` $ ”
il mio prompt mi apparira’ cosi’:
2.4.17#
Attenti all’uso delle virgolette (che avranno un paragrafo tutto per loro), ho usato il carattere “`” non le classiche virgolette “‘”, chiamato backticks o virgolette rovescie, ottenute con AltGr+virgoletta semplice. La variable PS2 determina l’aspetto del prompt secondario e viene visualizzato quando si digitano comandi incompleti. Questo succede quando abbiamo a che fare con comandi molto lunghi, possiamo digitare il comando su piu’ linee facendo precedere il comando invio da una barra rovesciata (backslash), a quel punto la shell capira’ che non abbiamo terminato e ci presentera’ il prompt secondario che significa che sta attendendo successivi comandi. Se per sempio vogliamo vedere come si presenta il prompt secondario nella nostra shell possiamo digitare
root@poldo:#if [ -f /etc/profile ]; then
poi premiamo invio e ci accorgeremo di avere un prompt diverso il mio e’:
>
in questo caso non abbiamo dovuto far precedere l’invio da una barra rovescia perche’ la shell riconosce i suoi costrutti di programmazione, volendo si potrebbe digitare un semplice echo $PS2 per ottenere direttamente il valore della variabile. Tutto quello che e’ stato detto per PS1 vale in linea di massima per PS2.

——————Il file storico————————————-
La shell e’ in grado di ricordare i comandi immessi dall’utente che normalmente sono salvati nel file ~/.bash_history e possono essere richiamati premendo i tasti freccia in su’ e freccia in giu’, questo comportamento puo’ essere modificato configurando le variabili:
HISTSIZE
HISTFILE
HISTFILESIZE
E’ da ricordare che per abitudine le variabili di ambiente vengono indicate usando lettere maiuscole a differenza dele locali per cui si usano le minuscole. Queste variabili sono definite in /etc/profile ma possono essere sovrascritte in ~/.bash_profile.
HISTSIZE
Vero il numero massimo dei comandi da memorizzare nel file storico normalmente il valore preimpostato e’ 500.
HISTFILE
Indica il file che deve essere usato per contenere i comandi digitati normalmente il valore preimpostato e’ ~/.bash_history, puo’ anche non essere impostato, lo storico si limitera’ alla sessione di lavoro corrente, puo’ essere rediretto con una pipe su /dev/null (vedremo in seguito).
HISTFILESIZE
Determina la grandezza fisica massima che puo’ avere il file dello storico.
Se volessimo cancellare tutto lo storico impartiremo il comando:
pinco-pallino@poldo:~$ history -c

——————Le variabili della posta—————————-
La shell ha le seguenti variabli che influenzano le funzioni di posta
MAIL
MAILCHECK
MAILPATH
MAIL_WARNING
Queste variabili sono normalmente definite nel file /etc/profile ma possono essere sovrascritte nel file ~/.bash_profile .
MAIL
Quando un messaggio di posta arriva all’utente, il suo contenuto e’ scritto su di un file, questo file e’ definito dalla variabile MAIL che normalmente contiene il valore /var/spool/mail/nome_utente . Si puo’cosi’ indicare alla shell il file da controllare per l’arrivo di nuovi messaggi.
MAILCHECK
Questa variabile definisce l’intervallo di tempo che deve trascorrere prima che la casella di posta locale venga controllata. Il valore preimpostato e’ 60 che significa che la shell controllera’ la directory ogni minuto.
MAILPATH
Questa variabile definisce il percorso per raggiungere le directory di posta normalmente contiene il valore /var/spool/mail . Puo’ essere usata anche per personalizzare il messaggio che notifica l’arrivo della nuova posta, esempio:
MAILPATH=’/var/spool/mail/nome_utente “Hai posta….!”‘
MAIL_WARNING
Se questa variabile e’ definita, la shell vi informera’ con un messaggio, se state leggendo un messaggio gia’ letto in precedenza. Visto l’uso ormai consolidato dei client di posta come pine, mutt, o altri grafici questa variabile e’ ormai poco usata.

——————————-Varie——————————–
Ci sono direttive e variabili che non sempre sono usate, di seguito brevemente le piu’ frequenti.
set -o notify
ci informa che un programma che avevamo avviato in background, facendo cioe’ seguire il nome comando dal carattere “&”, e’ terminato stampando il messaggio [1]1+ Done nome_comando
Puo’ essere usata in /etc/profile oppure in ~/.bash_profile.
TMOUT
Questa variabile specifica quanto tempo la shell attendera’ per l’inserimento del nome utente o della password al login.
TMOUT=60
attendera’ un minuto prima di reinizializzare il login.
set -o noclobber
Questa direttiva impedira’ la redirezione dell’output su di un file gia’ esistente. Per aggirare questa limitazione il carattere di redirezione dovra’ essere seguito da un carattere di pipe (approfondito in seguito).
Esempio:
root@poldo:#echo “testo di prova” >| ~/.test_file
si evita in questo modo la sovrascrittura accidentale di un file.
Puo’ essere usata in /etc/profile oppure in ~/.bash_profile, per revocare la direttiva possiamo usare il comando:
unset +o noclobber

———————-Gli alias————————————-
Gli alias si possono definire come comandi “accorciati”. Se vogliamo chiamare un comando lungo in maniera piu’ mnemonica possiamo assegnarlo ad un alias. Se per esempio volessimo evitare di digitare ogni volta il comando:
ls -aF –color
potremmo assegnarlo nel file /etc/bashrc oppure ~/.bashrc nel seguente modo:
alias ls=’ls -aF –color’
Notare ancora una volta l’uso delle virolette rovescie. Possiamo definire quanti alias ci servono senza limiti.

——————–I permessi sui file—————————–
Una delle molte cose che differenzia un sistema Unix da windows sono i permessi e il concetto di appartenenza di un file. Ogni file nello Unix e’ di proprieta’ di un utente e di un gruppo. Gli utenti possiedono i file creati da loro stessi, e quelli attribuiti all’utente dall’utente root con il comando “chown”. Il gruppo di un file viene dedotto dal sistema in base al gruppo di appartenenza dell’utente, visto che un utente puo’ appartenere a piu’ gruppi puo’ cambiare gruppo di appartenenza a un file con il comando “chgrp”. Si puo’ sapere a che gruppo appartenga un utente usando il comando “groups”.
chown [nome_utente] [nome_file]
chgrp [nome_gruppo] [nome_file]
groups [nome_utente]
I permessi definiscono chi puo’ fare qualcosa, e che cosa puo’ essere fatto con un file. Sono divisi in quattro gruppi, i primi tre di uso frequente, il quarto di uso meno frequente e piu’ complesso, per cui ci limiteremo a una sua descrizione meno approfondita. Il permesso sui gruppi definisce che cosa un utente appartenente a quel gruppo puo’ fare con il file, l’universale quello che un utente non appartenente al gruppo puo’ fare. Ogni sezione della terna utente-gruppo-altri e’ composto da tre bits che quindi generano tre stati di settato/non_settato, i campi indicano:
lettura -il file puo’ essere letto in caso di directory e’ possibile
dare il comando ls nella directory viene indicato dal
carattere “r”.
scrittura -il file puo’ essere scritto in caso di directory e’ possibile
creare o cancellare i file all’interno viene indicato dal
carattere “w”.
esecuzione -il file puo’ essere mandato in esecuzione in caso di
directory e’ possibile usare il comando cd /nome_directory
viene indicato dal carattere “x”.
La rappresentazione numerica dei permessi non e’ molto difficile. Le tre categorie utente-gruppo-altri, che contengono ciascuna tre permessi, vengono considerate come una sequenza di tre cifre in formato ottale. Ogni cifra ottale corrisponde a tre cifre in binario (base 2), che sono sequenze di uno e di zero, quindi abbiamo tre gruppi di tre cifre che ci permettono di settare tutti i permessi. Dunque ogni cifra ottale ci restituisce tre cifre binarie, per esempio la cifra ottale 6 corrisponde al numero binario 110 che quindi imposta a 1 il permesso di lettura, a 1 il permesso di scrittura e a 0 quello di esecuzione.
Vi riporto per comodita’ la tabella:
base 8 (ottale) base 2 (binario)
0 000
1 001
2 010
3 011
4 100
5 101
6 110
7 111
Come appare piu’ chiaro un numero ottale ha il corrispondente binario che puo’ essere interpretato come una terna di valori booleani. Ci possiamo ricavare un’altra tabella:
permesso numero binario
r 4 100
w 2 010
x 1 001
Dunque per determinare il numero totale da specificare per ogni elemento della terna utente-gruppo-altri bastera’ sommare i valori relativi.
Ultimo esempio:
proprietario rx 4+1=5
gruppo r 4
altri r 4
544 ovvero 101 100 100
digitando
chmod 544 nome_file
gli attribuiremo i seguenti permessi:
r-xr–r–
E’ possibile impostare, ma solo per gli eseguibili e le directory anche i bit di suid e sgid che vengono usati per modificare il comportamento standard dei permessi, ma possono causare problemi di sicurezza e meritano una discussione approfondita che va al di la’ delle intenzioni di questa mini guida.
———————————————————————————————————————————————————–
———————————————————————————————————————————————————–
Utilizzate la shell Cap.2 PDF Stampa E-mail
Scritto da Patrizio
martedì 12 dicembre 2006
Seconda parte della mini-guida dedicata all’utilizzo della shell Bash
——————-Programmazione con la Shell——————-

————————Sommario parte 2————————-
Introduzione alla programmazione in ambiente shell Bash
Il primo programma
Il secondo programma
Ancora commenti
Ancora variabili
Strutture di controllo
Il costrutto if
Il ciclo while
Il ciclo until
Il costrutto for
Il costrutto case
Le virgolette
Le operazioni con i numeri

——Introduzione alla programmazione in ambiente shell Bash——–
Come tutte le shell disponibili in Linux la shell Bash non solamente permette all’utente di digitare i comandi, ma include nell’eseguibile un vero e proprio mini linguaggio di programmazione, permettendoci di codificare script, cioe’ piu’ o meno brevi sequenze di istruzioni, da qui la definizione di linguaggio di scripting. Molti dei programmi che normalmente si utilizzano in Linux sono script di shell, quindi per comprendere il loro funzionamento ed eventualmente modificarli, e’ indispensabile conoscere le basi del linguaggio e la sua sintassi. Prima di iniziare e’ opportuno rimarcare la differenza tra linguaggi di scripting e linguaggi compilati. Generalmente i programmi compilati sono molto piu’ veloci e potenti dei programmi di scripting, ma altrettanto spesso questa velocita’ e potenza non giustifica la complessita’ e il tempo necessario per lo sviluppo. Un programma compilato viene generato da un file di testo denominato sorgente, che viene appunto processato da un compilatore che lo traduce in linguaggio macchina restituendoci un eseguibile binario (non piu’ un semplice file di testo ascii quindi), questo eseguibile dipende pesantemente dalla piattaforma su cui e’ stato compilato e non e’ eseguibile su altre piattaforme, esempio per tutti il linguaggio C. Una via di mezzo e’ rappresentata dai linguaggi semi-compilati come il Java in cui si ha solo una precompilazione del sorgente di testo, che viene processato per ottenete il bytecode un file binario che verra’ eseguito dall’interprete Java installato sul sistema. Un classico linguaggio interpretato, oltre allo shell scripting ovvio, e’ l’html in cui il sorgente e’ e rimane un semplice file di testo, e’ l’interprete incorporato nel browser che si occupa di tradurre i caratteri o le sequenze di caratteri speciali nelle opportune istruzioni di visualizzazione. I programmi interpretati sono dunque piu’ lenti, vista la necessaria interpretazione “al volo” ma sono facilmente e velocemente modificabili, e sono ottimi per le piccole applicazioni. Altri esempi di linguaggi interpretati sotto GNU/Linux sono il Perl, il Lisp, il Tcl, ecc…
Per scrivere semplici programmi interpretabili dalla shell e’ richiesta la conoscenza di almeno i principali comandi di Gnu/Linux, e la capacita’ di usare un editor di testo, meglio se non visuale come emacs, vim, nano, o pico; ma anche kate, gedit o xedit svolgono egregiamente il loro compito, fate voi. E’ anche buona abitudine non provare i propri script come utente root per evitare spiacevoli danni a file di sistema.

——————–Il primo programma——————————
Per non infrangere la tradizione cominceremo con un programma che stampa a video l’ignobile frase “Ciao mondo”. Quindi aprite un editor di testo e scrivete:
#!/bin/bash
echo “Ciao mondo”
la prima riga avvisa Linux che vogliamo che tutto cio’ che segue sia passato all’interprete bash, che in questo caso si trova nella directory /bin ma che puo’ trovarsi in un posizione non standard che possiamo indicare sotto forma di percorso. Il prossimo passo sara’ salvare lo script col nome di ciao.sh, successivamente dovremo renderlo eseguibile settando i dovuti permessi, quindi:
root@poldo:#chmod 700 ./ciao.sh
io lo sto facendo da root ma voi entrate nel sistema come utente.
Una volta settati i permessi possiamo avviare il nostro programma semplicemente digitando:
root@poldo:#./ciao.sh
Il vostro primo programma vi salutera’, e tutto questo ci servira’ a ricordare la sequenza, scrittura-salvataggio-permessi, che sta’ alla base di tutto. Cosa ha fatto il programma? Ha semplicemente stampato a video la scritta Ciao mondo, ma come ha fatto? Ha semplicemente usato un comando di shell, il comando “echo” che prende un argomento e lo stampa a video. Un argomento e’ qualsiasi stringa o numero che segue il comando, in questo caso la stringa “Ciao mondo” e’ l’argomento passato al comando “echo”. Quando noi dalla shell digitiamo il comando ls /var/log passiamo al comando “ls” l’argomento “/var/log”. Lo stesso effetto del nostro programma, vista la sua semplicita’ era ottenibile da shell digitando:
root@poldo:#echo “Ciao mondo”
ma era solo a scopo didattico.

——————–Il secondo programma————————–
Scriveremo un programma un tantino piu’ utile, spostera’ tutti i file della directory corrente dentro una cartella che creeremo, cancellera’ la directory creata e i file al suo interno, e alla fine la ricreera’. Tutto cio’ sarebbe possibile da shell digitando i seguenti comandi:
mkdir trash
mv * trash
rm -rf trash
mkdir trash
ma noi metteremo tutti i comandi in un file di shell, quindi apriamo l’editor e digitiamo :
#!/bin/bash
mkdir trash
mv * trash
rm -rf trash
mkdir trash
echo “file cancellati e directory ricreata con successo”
Salviamolo con il nome di test.sh, diamogli i permessi con il chmod 700, ed eseguiamolo digitando ./test.sh .
Quindi anche se siamo agli inizi se dobbiamo compiere azioni ripetitive consideriamo la possibilita’ di scriverci un file di shell.

—————————-Ancora commenti————————-
Abbiamo visto precedentemente che i commenti vengono ottenuti facendo precedere come primo carattere della linea il simbolo “#”, l’unica eccezione e’ rappresentata dall’invocazione dell’interprete nella prima riga di ogni script cioe’ la sequenza #!/bin/bash . Fate uso dei commenti il codice sara’ piu’ chiaro per voi e per gli altri.

—————————–Ancora variabili———————–
Abbiamo gia’ detto che le variabili sono fondamentalmente “scatole” che contengono valori. Avremo bisogno spesso di crearci variabili per motivi diversi, per memorizzare un valore immesso dall’utente, per effettuare calcoli o per memorizzare stringhe. Per fare un esempio pratico aprite il vostro editor e create un file di shell che contenga le seguenti righe:
#!/bin/bash
x=12
echo “Il valore della variabile x=$x”
Salvatelo dategli i giusti permessi ed eseguitelo.
Quello che abbiamo fatto e’ stato assegnare alla variabile x il valore di 12, notate ancora una volta che non ci deve essere spazio tra i termini, il valore della variabile puo’ essere recuperato anteponendo il suffisso “$” al nome della variabile. Le variabili possono essere sovrascritte e conterranno il valore dell’ultima assegnazione, per esempio
#!/bin/bash
x=12
echo “Il primo valore della variabile x=$x”
x=”a”
echo “Il secondo valore della variabile x=$x”

———————–Strutture di controllo——————-
Le strutture di controllo permettono ai nostri programmi di prendere delle “decisioni”, di essere molto piu’ compatti ed eleganti, e sopratutto di gestire gli eventuali errori. Quello che abbiamo fatto finora e’ fornire all’interprete una serie di istruzioni da eseguire. Se noi per esempio creiamo un file di shell chiamato test1.sh che contenga i seguenti comandi:
#!/bin/bash
cp /etc/miofile .
echo “Copiato.”
Il programma copierebbe il file /etc/miofile nella directory corrente e stamperebbe a video la stringa “Copiato.”. Il programma funzionera’ ad una condizione, che esista un file chiamato miofile nella directory /etc, altrimenti otterremmo dalla shell una risposta del tipo:
root@poldo:#./test1.sh
cp: /etc/miofile: No such file or directory
“Copiato.”
Possiamo osservare che c’e’ un problema, non e’ sicuro che tutti quelli che eseguono questo programma abbiano il file miofile nella directory /etc, sarebbe meglio se il programma controllasse l’esistenza di /etc/miofile prima di provare a copiarlo. Scrivendo il procedimento logico in pseudo-codice poteremmo dire:
SE /etc/miofile esiste, ALLORA
copia /etc/miofile nella directory corrente
e stampa a video il messaggio “Copiato.”
ALTRIMENTI
stampa a video il messaggio “il file non esiste”
Come e’ possibile ottenere un risultato come questo in un programma di shell? Semplice usando le strutture, o i costrutti, di controllo che la bash ci mette a disposizione, cioe’: if, while, until, for e case. Ogni struttura di controllo necessita di un comando di apertura e uno di chiusura, un po’ come i tag in html. Per esempio la struttura di controllo “if” comincia appunto con “if” e termina con “fi”. Le strutture di controllo sono funzioni incluse nella shell nativamente, quindi a differenza di quanto fatto finora non facciamo uso di comandi esterni. Cominciamo ad esaminarle.

———————-Il costrutto if—————————
if … else … elif …fi
Uno dei costrutti piu’ usati e’ “if” che ci permette di modificare il flusso del programma al verificarsi di una condizione. Per usare il costrutto “if” dobbiamo usare il comando di test che puo’ essere sottinteso dall’uso delle parentesi, in pratica possiamo riscrivere il codice di prima cosi’:
#!/bin/bash
if test -f /etc/miofile
then
# il file esiste quindi lo copio e stampo il messaggio
cp /etc/mia_var .
echo “Copiato.”
else
# il file non esiste quindi stampo il messaggio e esco
echo “il file non esiste”
exit
fi
Notare che la tabulazione non e’ obbligatoria ma rende il codice piu’ leggibile, aiutando a separare i blocchi di istruzioni. Salviamo il programma con il nome di test2.sh, diamogli i giusti permessi ed eseguiamolo con il solito ./test2.sh. La parola chiave test che controlla se il file esiste, puo essere sostituita dalle parentesi quadre, facendo attenzione a lasciare uno spazio prima degli argomenti, notare anche il punto e virgola che separa le istruzioni. Tutto quello che si trova dopo il punto e virgola viene interpretato come si trovasse su una riga a se’ stante.
Esempio:
if [ -f /etc/miofile ]; then
I controlli che la shell ci permette di fare su di un file sono i seguenti:
-d controlla se il file e’ una directory
-e controlla se il file esiste
-f controlla se il file e’ un file regolare
-g controlla se il file ha il bit SGID settato
-r controlla se il file e’ leggibile dall’utente che esegue lo script
-s controlla se la dimensione del file non e’ 0
-u controlla il file ha il bit SUID settato
-w controlla se il file e’ scrivibile
Il costrutto “else” viene usato per indicare al programma l’azione da compiere se la condizione non e’ soddisfatta. C’e’ anche il costrutto “elif” che e’ la somma dei costrutti “else” e “if” che permette di evitare un susseguirsi di “if” quando si vogliono testare piu’ condizioni. Quando si vuole testare una variabile e’ buona norma includerla dentro doppie virgolette, affinche’ venga espansa correttamente.
Esempio:
if [ "$mia_variabile" -eq 5 ]; then

———————Il ciclo while—————————-
while … do … done
Il costrutto “while” viene definito un costrutto ciclico. Fondamentalmente il suo significato in inglese ci descrive cosa fa’, infatti il significato e’ “mentre”. Potremmo semplificare in pseudo-codice dicendo:
MENTRE la condizione da testare e’ vera
FAI un compito
FINO A CHE la condizione di partenza non e’ piu’ vera.
Esempio:
#!/bin/bash
x=0; # assegnoall variabile x il valore 0
while [ "$x" -le 10 ]; do
echo “Il valore di x: $x”
# incremento ad ogni ciclo il valore di x di una unita’
x=$(expr $x + 1)
done
Possiamo vedere che abbiamo usato il comando test nella sua forma contratta, con le parentesi quadre per controllare lo stato della variabile x e sapere se era minore o uguale a 10, e mentre questo valore aumentava in virtu’ dei comandi della linea 6, finche’ non si raggiuge il valore 10, viene stampato il valore attuale.
Come per i files ci sono test predefiniti per i numeri:
x -eq y Vero se x e’ equivalente a y
x -ne y Vero se x non e’ equivalente y
x -gt y Vero se x e’ maggiore y
x -lt y Vero se x minore y
x -ge y Vero se e’ maggiore o equivalente
x -le y Vero se minore o equivalente
Mentre per confrontare le stringhe di caratteri abbiamo:
x = y Vero se x e’ uguale y
x != y Vero se x non e’ uguale a y
-n x Vero se x non e’ nullo o vuoto
-z x Vero se x e’ nullo o vuoto
Riprendendo l’esempio appena fatto un altro dubbio vi potrebbe venire
osservando la riga
x=$(expr $x + 1)
Abbiamo detto che incrementa di un unita’ la variabile x, ma dobbiamo chiarire cosa significa $(…). Questo e’ un modo per dire all’interprete della shell che vogliamo sia eseguito il comando “expr”, e vogliamo che il risultato sia assegnato alla variabile x. Ogni comando tra le parentesi verra’ eseguito.
Esempio:
#!/bin/bash
io=$(whoami)
echo “io sono $me.”
Provatelo e capirete meglio, potremmo anche riscriverlo in forma breve come:
#!/bin/bash
echo “io sono $(whoami).”
In seguito vedremo un’altro metodo per assegnare ad una variabile il risultato di un comando.

———————–Il ciclo until—————————
until … do … done
Fondamentalmente simile al precedente invece che “mentre” il costrutto ciclera’ “fino a che” la condizione e’ vera. Mettete in esecuzione l’esempio e capirete la sottile differenza osservando il numero dei cicli.
#!/bin/bash
x=0
until [ "$x" -ge 10 ]; then
echo “Current value of x: $x”
x=$(expr $x + 1)
done

———————-Il costrutto for—————————
for … in … do … done
Il costrutto for e’ usato fondamentalmente per ripetere un dato comando un certo numero di volte. Per esempio volendo stampare dieci punti potremmo scrivere un file di shell cosi’:
#!/bin/bash
echo -n “Incomincio a stampare ”
for mia_var in 1 2 3 4 5 6 7 8 9 10; do
echo -n “.”
echo ” finito.”
done
L’opzione -n passata al comando “echo” prima dell’argomento fa si’ che il comando non emetta il carattere di nuova linea (/n o newline) che farebbe andare a capo. La variabile mia_var conterra’ di volta in volta i valori da 1 a 10, stampando un punto per ogni valore. Per chiarire possiamo provare un altro script:
#!/bin/bash
for x in piero paolo stefano; do
echo “Il valore della variabile x : $x”
done
Vedrete che verra’ stampato di volta in volta il valore della variabile. Per fare un’esempio piu’ utile aggiungeremo il suffisso .txt a tutti i file nella directory corrente.
#!/bin/bash
for file_presenti in *; do
echo “Aggiungo .txt al file $file_presenti…”
mv $file_presenti $file_presenti.txt
done
Il carattere “*” e’ un carattere jolly che si espande in “tutto nella directory corrente”, il comando “mv” e’ usato per rinominare il file.

———————Il costrutto case————————–
case … in … done
Il costrutto “case” e’ molto simile al costrutto “if”, fondamentalmente viene usato per testare una condizione contro valori noti senza usare svariati “if”.
Un esempio chiarira’:
#!/bin/bash
x=5 # assegno a x il valore 5
# incomincio a testare x
case $x in
0) echo “Il valore di x: 0.”
;;
5) echo “Il valore di x: 5.”
;;
9) echo “Il valore di x: 9.”
;;
*) echo “Valore sconosciuto”
esac
Il costrutto “case” testera’ il valore di x contro tre valori noti, prima controllera’ se il valore e’ 0, successivamente se e’ 5, al termine se il valore e’ 9. Se nessuna delle condizioni si avverera’ verra’ eseguita la il blocco di codice della condizione “*” che abbiamo visto essere espansa come “qualsiasi valore”. Ogni blocco di codice che segue una condizione deve essere terminato con la sequenza di caratteri “;;”. Usando il ciclo “if” avremmo dovuto scrivere:
#!/bin/bash
x=5 # assegno a x il valore 5
if [ "$x" -eq 0 ]; then
echo “Il valore di x: 0.”
elif [ "$x" -eq 5 ]; then
echo “Il valore di x: 5.”
elif [ "$x" -eq 9 ]; then
echo “Il valore di x: 9.”
else
echo “Valore sconosciuto”
fi
Il costrutto e’ sicuramente meno leggibile.

————————Le virgolette—————————–
Le virgolette sono molto importante nello shell scripting, ci sono tre tipi di virgolette ed ognuno ha un significato diverso per l’interprete della shell.
” virgoletta doppia
‘ virgoletta semplice
` virgoletta invertita
Le virgolette DOPPIE sono usate spesso per impostare un valore stringa e per preservare gli spazi nelle stringhe.
Esempio:
x=”stringa con quattro parole”
la variabile conservera’ la stringa come un valore singolo, cioe’ una stringa formata da caratteri e da spazi, in sintesi un solo argomento. Applichiamo quanto detto ai comandi, se noi digitassimo:
mkdir ciao mondo
ls -F
avremmo:
ciao/ mondo/
cioe’ avremmo creato due directory distinte perche’ il comando tratterebbe quello che lo segue come due argomenti diversi. Ma se invece digitiamo:
mkdir “ciao mondo”
ls -F
avremmo:
ciao/ ciao mondo/ mondo/
cioe’ il comando interpreterebbe la stringa come un unico argomento. Usate con le variabili ne espandono il valore contenuto.
Le virgolette SEMPLICI si usano quasi sempre con le variabili, infatti una variabile inclusa in virgolette semplici, al contrario delle doppie, non verra’ espansa nel corrispondente valore.
Un esempio:
#!/bin/bash
x=5
# uso le doppie virgolette
echo “Usando le doppie virgolette x : $x”
# uso le virgolette semplici
echo ‘Usando le virgolette semplici x : $x’
Anche le virgolette semplici fanno si’ che i termini inclusi vengano considerati un argomento singolo.
Le virgolette ROVESCIATE sono completamente diverse dalle precedenti due.
Ricordate uno degli esempi precedenti quando scrivemmo :
x=$(expr $x + 1)
grazie alle virgolette rovesciate possiamo riscriverlo cosi’:
x=`expr $x + 1`
in pratica come avevamo gia’ visto assegnamo il risultato di un comando o di una pipe di comandi ad una variabile.

——————-Le operazioni con i numeri———————
La shell Bash ci permette, come abbiamo gia’ visto, di eseguire espressioni aritmetiche. Si possono effettuare operazioni in due modi, uno l’abbiamo gia’ incontrato ed e’:
x=`expr $x + 1`
l’altro e inserire l’espressione da valutare tra doppie parentesi, attenzione doppie non singole come nell’esempio di prima, e cioe’:
x=$(($x+1))
possiamo verificare con:
#!/bin/bash
x=8
y=4
z=$(($x + $y))
echo “La somma di $x + $y = $z”
Gli operatori aritmetici messi a disposizione sono:
Addizione +
Sottrazione -
Moltiplicazione *
Divisione /
Resto o Modulo %
Sono le principali operazioni, tranne resto o modulo che restiuisce appunto il resto di una divisione.
Esempio:
#!/bin/bash
x=5
y=3
somma=$(($x + $y))
sottrazione=$(($x – $y))
moltiplicazione=$(($x * $y))
divisione=$(($x / $y))
modulo=$(($x % $y))
echo “Somma: $somma”
echo “Sottrazione: $sottrazione”
echo “Moltiplicazione: $moltiplicazione”
echo “Divisione: $divisione”
echo “Modulo: $modulo”
————————————————————————————————————————————————————
————————————————————————————————————————————————————
Utilizzate la shell Cap.3 PDF Stampa E-mail
Scritto da Patrizio
martedì 12 dicembre 2006
Terza parte della mini-guida dedicata all’utilizzo della shell Bash
———————–Programmazione con la Shell——————-

—————————Sommario parte 3————————–
Input dall’utente
Le funzioni
Intercettare i segnali di sistema
I costrutti AND e OR
Gli argomenti
Le redirezioni e le pipe
Files temporanei
Valori di ritorno
Conclusioni

————————Input dall’utente—————————–
Vedremo ora come leggere i valori immessi dall’utente per usarli nei nostri programmi, useremo per questo il comando “read” che e’ un comando interno della shell che copiera’ l’input dell’utente in una variabile.
Esempio:
#!/bin/bash
# programma che prende l’input dall’utente e lo saluta
echo -n “Inserisci il tuo nome: ”
read nome_utente
echo “Ciao $nome_utente !”
Il comando “read” apettera’ che l’utente immetta qualcosa e prema ENTER o INVIO, e aspettera’ all’infinito che venga premuto il tasto INVIO. Se l’utente non immette nulla e preme INVIO read sara’ eseguito ugualmente e il programma continuera’ con l’istruzione successiva. Cominciamo a controllare dunque che l’utente immetta qualcosa:
#!/bin/bash
# programma che prende l’input dall’utente e lo saluta
echo -n “Inserisci il tuo nome: ”
read nome_utente
#controlliamo se l’utente ha immesso qualcosa
if [ -z "$nome_utente" ]; then
echo “Non hai digitato nulla!”
exit
fi
echo “Hello $nome_utente !”

————————–Le funzioni———————————
Le funzioni rendono la programazione meno ripetitiva e piu semplice, ci permettono di suddividere il programma che dobbiamo scrivere in tanti piccoli sottoprogrammi, per essere stringati una funzione e’ un pezzo di codice che accetta o no valori in entrata, compie delle azioni, e puo’ emettere dei risultati siano essi semplici valori booleani di ritorno o dati piu’ complessi.
Esempio di funzione semplice:
#!/bin/bash
#dichiariamo la funzione ciao()
ciao()
{
echo “Sono nella funzione ciao()”
}
echo “Sto per chiamare la funzione ciao()…”
# chiamata della funzione ciao()
ciao
echo “Sono uscito dalla funzione ciao()”
Mandando in esecuzione questo pezzo di codice, ci accorgiamo che l’unica cosa che fa’ e’ stampare un messaggio, ovviamente le funzioni possono fare cose molto piu’ complesse, ma questo ci serve per osservarne la struttura. La stampa a video del messaggio contenuto nella dichiarazione di funzione e’ avvenuta quando abbiamo richiamato la funzione, dopo averla precedentemente dichiarata. Infatti la bash quando incontra la linea che richiama la funzione ciao va’ a ritroso, perche’ per usare una funzione bisogna averla dichiarata in precedenza, cercando il nome funzione seguito da due parentesi tonde oppure la parola chiave function che noi non abbiamo usato perche’ facoltativa.
Volendo avremmo potuto scrivere:
function ciao()
{
echo “Sono nella funzione ciao()”
}
La dichiarazione di funzioni quindi consta della parola chiave “function” che e’ facoltativa, del nome che assegniamo alla funzione seguito da apertura di parentesi tonda, e successiva chiusura, per leggibilita’ un ritorno a capo, una apertura di parentesi graffe, il blocco di codice che la compone, la chiusura delle parentesi graffe.
function nome_funzione()
{ #inizio blocco che verra’ eseguito
istruzioni
} #fine blocco che verra’ eseguito
Tutto quello che si trova tra le parentesi graffe, dichiarazione di variabili, espressioni complesse, ecc. si definisce di ambito locale, cioe’ i valori sono definiti e hanno un senso solo all’interno di essa. Se chiamiamo una funzione prima di averla definita otterremmo in risposta un messaggio di errore “command not found”, quindi e’ buona norma mettere le dichiarazioni di funzione raggruppate in testa al nostro script.
Facciamo un esempio piu’ completo:
#!/bin/bash
# admin.sh un tool stupidino
# function nuovo_utente() la funzione che crea un nuovo utente
# la dichiariamo in cima allo script prima della chiamata
nuovo_utente()
{
echo “Stai per aggiungere un nuovo utente…”
sleep 2 #semplicemente sospende per due secondi l’esecuzione
adduser #manda in esecuzione il comando di shell “adduser”
}
#iniziamo lo script
echo “1. Aggiungi un utente”
echo “2. Esci”
echo “Digita la scelta: ”
read scelta
case $scelta in
1) nuovo_utente #se il confronto e’ positivo chiamiamo nuovo_utente
;;
*) exit #in tutti gli altri casi terminiamo col predefinito
;;
esac
Per eseguire questo script bisogna entrare nel sistema con l’account di root, essendo il comando “adduser” eseguibile solo da root.

——————-Intercettare i segnali di sistema—————–
L’argomento e’ un po’ complesso ma lo accenniamo. E’ possibile grazie al comando di shell “trap” intercettare i segnali si sistema. Se noi durante l’esecuzione di uno script o di un comando premiamo la combinazione di tasti Ctrl+c, mandiamo allo script un segnale di interrupt che fara’ terminare l’esecuzione. Possiamo intercettare le principali chiamate e far continuare l’esecuzione del nostro programma, usando appunto il comando “trap”, per conoscere i segnali che puo’ gestire digitate trap -l, la sua sintassi e’:
trap azione segnale
L’azione e’ tutto cio’ che vogliamo accada se il segnale di interrupt viene chiamato. I segnali possono essere indicati sia in forma numerica, sia in forma letterale, nel secondo caso si devono omettere le prime tre lettere, generalmente “SIG”, per esempio se volessimo intercettare il segnale di interrupt “SIGINT” (codice numerico 2) dovremmo usare la stringa “INT”.
Esempio:
#!/bin/bash
# usiamo il comando trap
# catturiamo la sequenza di tasti Ctrl-c ed eseguiamo la funzione spiacente
trap spiacente INT
# la funzione spiacente stampa semplicemente un messaggio
spiacente()
{
echo “Spiacente, non puoi farlo”
sleep 3
}
# contiamo alla rovescia da 10 a 1
for i in 10 9 8 7 6 5 4 3 2 1; do
echo “mancano $i secondi ”
sleep 1
done
echo “…finito”
Adesso salviamo, rendiamo eseguibile, avviamolo, e mentre lo script conta proviamo a premere Ctrl+c, normalmente l’esecuzione si sarebbe interrotta, ma in questo caso il segnale di interrupt e’ stato intercettato da “trap” che invece di uscire ha richiamato la funzione spiacente(). Se si vuole semplicemente far ignorare al programma il segnale di interrupt basta passargli al posto dell’azione due virgolette semplici vuote ” ” ” , se vogliamo annullare l’effetto del comando “trap” dobbiamo resettarlo passandogli un trattino ” – “.
trap ” INT
trap – INT
Il reset riportera’ la sequenza di tasti alla sua normale funzione.

——————-I costrutti AND e OR————————–
Abbiamo gia’ parlato delle strutture di controllo (“if…elif..ecc”), ma abbiamo un paio di cosette da aggiungere: le direttive AND, generalmente indicata con la sequenza di caratteri “&&”, e la direttiva OR, indicata con “||” (doppio pipe il carattere sopra “”).
La sintassi della direttiva AND e’:
prima_condizione && seconda_condizione
La direttiva AND controlla prima la condizione a sinistra, se restituisce vero, controlla quella di destra, se ambedue sono soddisfatte continua con l’esecuzione del codice successivo. In pseudo-codice potremmo scrivere:
SE la prima condizione e’ vera E la seconda condizione e’ vera ALLORA…
Esempio:
#!/bin/bash
x=5
y=10
if [ "$x" -eq 5 ] && [ "$y" -eq 10 ]; then
echo “Entrambe le condizioni sono vere”
else
echo “Le condizioni non sono vere”
fi
Cambiate il valore di x in 12 e vedete cosa succede.
Il costrutto OR non si comporta molto differentemente, testa se la prima condizione e se e’ falsa passa alla seconda, se almeno questa e’ vera esegue i comandi, altrimenti passa ai comandi successivi.
In pseudo-codice:
SE la prima condizione e’ vera OPPURE la seconda condizione e’ vera ALLORA…
Esempio:
#!/bin/bash
x=3
y=2
if [ "$x" -eq 5 ] || [ "$y" -eq 2 ]; then
echo “Una delle condizioni e’ vera”
else
echo “Nessuna delle condizioni e’ vera”
fi
Questi costrutti servono spesso per evitare l’annidarsi di piu’ istruzioni “if”, anche se resta possibile farlo, il primo esempio sarebbe stato:
#!/bin/bash
x=5
y=10
if [ "$x" -eq 5 ]; then
if [ "$y" -eq 10 ]; then
echo “Entrambe le condizioni sono vere”
else
echo “Nessuna condizione e’ vera”
fi
fi

————————Gli argomenti————————
Avrete notato che la maggior parte dei comandi Linux non si limita ad eseguire un compito in maniera autonoma, ma spesso richiede delle informazioni extra che l’utente deve fornirgli, se la chiamata del comando e’ incompleta ci appare spesso il messaggio che ci suggerisce l’uso appropriato. Il comando “more” che serve a visualizzare un file, se digitato da solo produrra’ un messaggio che ci informa sul suo uso. Il comando si aspetta degli argomenti, cioe’ dei valori immessi dall’utente. Ora dobbiamo sapere che la shell utilizza delle variabili speciali per tenere in memoria questi valori.
Queste sono le variabili speciali utilizzate:
$# Contiene il numero dei parametri passati
$1-$n Contiene il valore singolo dei parametri ordinati per immissione (1-9)
$? Contiene il valore di uscita dell’ultimo comando
$0 Contiene il nome del programma
$* Contiene tutti i parametri ordinati per immissione ($1 $2 …).
“$@” Contiene tutti i parametri ordinati per immissione inclusi in doppie
virgolette (“$1″ “$2″ …).
Esempio:
#!/bin/bash
# script per visualizzare il primo argomento
# prima controlliamo se ci sono argomenti
if [ "$#" -ne 1 ]; then
echo “uso: $0 argomento ”
fi
echo “L’argomento pasato e’ $1″
Chiamatelo prima senza argomento e poi facendo seguire un numero o una stringa al comando e verificate cosa succede.

———————Le redirezioni e le pipe——————-
Normalmente quando eseguiamo un comando il suo risultato viene stampato a video. Per esempio il comando:
echo “Ciao mondo”
stampa la stringa “Ciao mondo”, perche’ lo ‘standard output’ del programma e’ la console. Ci sono tre canali predefiniti per i comandi in Linux, lo ‘standard input’, lo ‘standard output’ e lo ‘standard error’, spesso il secondo e il terzo coincidono per permetterci di vedere gli errori generati, ma altrettanto spesso gli errori, e quindi lo ‘standard error vengono rediretti su di un file di log. La redirezione ci permette di modificare i comportamenti standard del programma, i suoi operatori sono:
> redirige lo standard output su di un file sovrascrivendo i dati
>> redirige lo standard output su di un file appendendo alla fine i dati
Esempio
echo “Ciao mondo”> mio.file
cat mio.file
stampera’:
“Ciao mondo”
echo “mi appendero’ al file” >> mio.file
cat mio.file
stampera’:
“Ciao mondo”
“mi appendero’ al file”
Le pipe permettono di passare a un comando come argomento il risultato di un altro comando, possiamo cosi’ concatenare piu’ comandi per ottenere quello che vogliamo. Per iniziare concateneremo il risultato del comando “cat”, che tra le altre funzioni e’ utile per leggere un file, al comando grep, che ci restituisce le righe di un file che corrispondono ad un criterio di ricerca. Se volessimo trovare nel file /etc/passwd la riga che si riferisce all’utente “carognone” presente nel mio sistema potremmo digitare:
cat /etc/passwd | grep carognone
il risultato sarebbe
carognone:x:1002:100:users,,,:/home/carognone:/bin/bash
Il comando cat “passa” il contenuto del file al comando “grep” che esegue la ricerca e ci restituisce il risultato sullo standard output.
Possiamo concatenare pipe e redirezioni:
cat /etc/passwd | grep carognone > mio.file
non apparira’ nulla perche’ lo indirizziamo sul file, leggiamo il file
cat mio.file
il risultato:
carognone:x:1002:100:users,,,:/home/carognone:/bin/bash

————————Files temporanei———————–
Spesso ci servira’ creare dei file temporanei su cu scrivere dei valori, o conservarli tra una chiamata ed un’altra dello script. La cosa importante da tenere a mente e’ che no possiamo rischiare di sovrascrivere file esistenti. Per fare questo ci serviamo della sequenza di caratteri “$$” che possiamo usare come prefisso o postfisso al nome del file.
Esempio:
creiamo un file
touch mio_file
controlliamo
ls
risultato:
mio_file
usiamo il postfisso
touch mio_file.$$
controlliamo
ls
risultato:
mio_file mio_file.689

——————–Valori di ritorno————————–
Molti programmi restiuiscono valori di ritorno che ci informano sul risultato della loro esecuzione, se consultiamo la pagina man di “grep” leggeremo che il programma restituisce uno 0 se non riesce a trovare nulla, altrimenti un 1. Il perche’ dovremmo interessarci del valore di uscita di un programma ci sara’ chiaro con un esempio. Se noi volessimo sapere se un utente esiste nel sistema potremmo controlare con grep se e’ presente nel file /etc/passwd :
grep “asino” /etc/passwd
ora dato che “asino” non e’ un utente della mia macchina il risultato sara’ un prompt vuoto. Sarebbe opportuno avere un messaggio che ci avvisi che non e’ stato trovato nulla, quindi useremo la variabile speciale “$?” che contiene il valore di uscita del comando eseguito:
#!/bin/bash
# greppiamo per cercare l’utente
#e redirigiamo l’uscita su /dev/null un file che e’ paragonabile a un cestino
#in modo che non appaia nulla
grep “asino” /etc/passwd > /dev/null 2>&1
# controlliamo il suo valore di ritorno
if [ "$?" -eq 0 ]; then
echo “Utente trovato”
exit
else
echo “Utente non trovato”
fi
Questo e’ valido per i comandi della shell, ma come facciamo ad avere dei valori di ritorno dai nostri script? Semplice il comando exit accetta un argomento, che puo’ essere un numero da restituire. Normalmente 1 significa che c’e’ stato un errore, 0 che tutto e’ andato bene.
Esempio:
#!/bin/bash
if [ -f "/etc/passwd" ]; then
echo “Il file di password esiste”
exit 0
else
echo “Il file di password non esiste”
exit 1
fi
Usando i valori di ritorno possiamo passare dei valori ad altri script, che si comporteranno di conseguenza. Anche le funzioni possono avere dei valori di ritorno, grazie al comando “return”, che accetta un argomento numerico, il suo uso e’ simile al comando “exit” visto in precedenza.
Esempio:
controlla_passwd()
{
if [ -f "/etc/passwd" ]; then
echo “Il file di password esiste”
#faccio restituire il valore 0
return 0
else
#faccio restituire il valore 1
echo “Il file di password non esiste”
return 1
fi
}
# metto in una variabile il valore di uscita
mia_var=controlla_passwd
#controlliamo il valore testando il contenuto della vaiabile
if [ "$mia_var" -eq 0 ]; then
echo “Il file esiste”
exit 0
else
echo “Il file non esiste”
exit 1
fi

—————————Conclusioni————————-
Quanto detto illustra solo la minima parte delle potenzialita’ dello shell scripting e quindi dell’uso della shell. Sta a voi adesso sperimentare. Buona produttivita’ con GNU/Linux… E ricordate: Usate la Shell!
—————————————————————-
Riferimenti: ShElL

I commenti sono chiusi.