Aggiornato Giugno 2008
Aggiornato Maggio 2009
________________________________________________________________________________________
Linux script e Asterisk (by GF 2008)
_________________________________________________________________________________________________
Questo documento mira ad insegnare a chi ha una conoscenza di base del sistema operativo Linux una serie di comandi di shell di elaborazione del testo.
Dati in input
Sia assegnato il file di nome "prova"
| 1 2 3 4 5 6 bianco giallo verde blu bianco arancione rosso 1 2 10 11 12 13 |
Grep
Problema:
Ritornare tutte le righe che fanno match con una espressione regolare.
Note: ".*" indica una sequenza di un qualsiasi numero
di qualsiasi tipo di carattere
| grep "bianco.*blu" prova bianco giallo verde blu |
Problema:
Ritornare tutte le righe che NON fanno match con una espressione regolare.
Note: "-v" e' un NOT ovvero fa il reverse del risultato
| grep -v "bianco.*blu" prova 1 2 3 4 5 6 bianco arancione rosso 1 2 10 11 12 13 |
Problema:
Ritornare il numero di righe che fanno match con una espressione regolare
Note: "-c" indica di ritornare il numero di righe che fanno
match, o non fanno match (-cv) con una espressione regolare
| grep -c "bianco" prova 2 grep -cv "10" prova 3 |
Problema:
Ritornare il nome dei file che contengono/non contengono match con una
espressione regolare
Note: "-l" indica di ritornare il nome dei file che fanno
match con una regex. "-L" ne e' la negazione.
| grep -l "bianco" * bianco grep -L "bianco" * file1 file2 file3 |
Problema:
Ritornare la riga contenente il match e un certo numero di righe antecedenti o
successive
Note: "-A" indica di ritornare la riga che fa match e la
successiva, "-B" l'antecedente
| grep -A1 "bianco.*rosso" prova bianco arancione rosso 1 2 10 11 12 13 grep -B1 "bianco.*rosso" prova bianco giallo verde blu bianco arancione rosso |
Problema:
Ritornare la riga contenente il match e la posizione della riga nel file
Note: "-n" ritorna in numero di riga dove e' stato trovato
il match
| grep -n "bianco" prova 2:bianco giallo verde blu 3:bianco arancione rosso |
Grep avanzato
Enhanced regular expression
L'opzione "-E" permette di utilizzare le
enhanced regular expression. Il carattere speciale "\" (backslash) assume
ruolo differente nel caso di enhanced regexp dove si presuppone che un carattere
speciale sia un metacarattere piuttosto che un carattere letterale.
I metacaratteri "(, ),
{, }" vanno preceduti da "'\" nelle basic regular expression.
| 1 2 3 4 5 6 bianco giallo verde blu bianco (arancione 2) rosso 1 2 10 11 12 13 |
| grep "(arancione)"
prova
|
Le parentesi vengono interpretate come elementi di testo pertanto si cerca una match con "(arancione)" che non esiste |
| grep -E
"(arancione)" prova bianco (arancione 2) rosso |
In questo caso le parentesi vengono interpretate come metacaratteri, in quanto con il "\" sarebbero interpretate come elementi di testo. Quindi le parentesi indicano una subregexp che rappresenta una riga contenente "arancione" |
| grep -E
"\(arancione 2\)" prova bianco (arancione 2) rosso |
In questo caso si usa il "\" per indicare che le parentesi non sono metacaratteri ma caratteri regolari. |
| grep
"\(arancione\)" prova bianco (arancione 2) rosso |
Si vede come l'interpretazione del backslash nel caso di regular regexp e' invertito rispetto che nelle extended regexp. |
Come si evince da questo
esempio metacaratteri "(, ), {, }" vanno preceduti da "'\" nelle basic
regular expression.
| grep -E
".*2[[:space:]][0-9]{1,2}[[:space]]11.*" prova 1 2 10 11 12 13 grep ".*2[[:space:]][0-9]{1,2}[[:space]]11.*" prova grep
".*2[[:space:]][0-9]\{1,2\}[[:space]]11.*" prova |
Cerchiamo una riga contenente "2 " quindi un numero di una o due cifre e quindi un " 11"
Backreference
In una regexp un backreference e' un riferimento ad un match gia' ottenuto, gia' segnato con le parentesi tonde. I backreference si indicano con "\n" dove "n" e' un numero indicante il backreference.
Ad esempio "<h1>titolo</h1>" e' un elemento html indicante un titolo. Per fare match potremmo utilizzare "<h[1-9]>titolo</h[1-9]>". Tuttavia questo fa match anche con "<h1>titolo</h3>". Abbiamo bisogno di un riferimento all'indietro, ovvero di un backreference. Allora scrivendo "<h\([1-9]\)>titolo</h\1>" abbiamo il risultato voluto. Il riferimento all'indietro della posizione numero 1 indica la prima coppia di parentesi tonde che racchiudono il numero che ci interessa.
Un uso possibile del backreference e' anche quello di tirare fuori, dalle righe restituite dal grep, le parole che hanno fatto match. Per questo possiamo usare il comando "sed" insieme a cron. Questa e' una procedura valida per estrarre da file di testo dei dati variabili restituiti ad esempio, da comandi inviati a software amministrabili da remoto. Ad esempio si pensi ad un'analisi dell'output di un comando "show interfaces" di un router Cisco o di un comando "show channels" di una centrale Asterisk:
| cat prova | grep -E "1.*3" | sed
"s/1[[:space:]]\([0-9]\)[[:space:]]3.*/\1/" 2 |
Il cat manda a grep uno o piu' file di testo. Il grep tira fuori solo le righe che interessano, in questo caso quelle contenenti i numeri 1 e 3. Successivamente sed tira fuori il valore numerico tra il numero 1 e il numero 3. Per far cio' utilizza un backreference "\1" al valore numerico. Si noti che sed sostanzialmente cambia una riga sostituendola con la stringa di cui abbiamo fatto il backreference, che e' quella che interessa.
Sed
Consideriamo sempre il file di input in tabella 1, che ripresentiamo per comodita':
| 1 2 3 4 5 6 bianco giallo verde blu bianco arancione rosso 1 2 10 11 12 13 |
Il comando "sed" effettua trasformazioni sui testi, quali ad esempio ricerche e sostituzioni.
Problema:
Sostituire la parola 'bianco' con 'blu' in tutto il file
Note: la sintassi del comando sed utilizza lo slash ('/')
per delimitare le varie sezioni. "s" indica la sostituzione mentre 'g'
indica che vogliamo sostituite tutte le occorrenze in una riga e non solo la
prima (questo e' opzionale).
| sed 's/bianco/blu/g' prova 1 2 3 4 5 6 blu giallo verde blu blu arancione rosso 1 2 10 11 12 13 |
Problema:
Cancellare la parola "bianco" da tutto il file
Note: una cancellazione di una parola non e' altro che un
caso particolare di sostituzione
| sed 's/bianco//g' prova 1 2 3 4 5 6 giallo verde blu arancione rosso 1 2 10 11 12 13 |
Problema:
Sostituire la parola 'bianco' con 'blu' in righe specifiche del file
Note: aggiungiamo una nuova condizione al comando sed,
indicante su quali righe la sostituzione va effettuata. Questa condizione va a
inizio riga e indica il numero di riga. Se indicata tra "/", allora e' una
espressione regolare, che risolta indica su quali righe la sostituzione va
effettuata.
| sed '2 s/bianco/blu/g' prova 1 2 3 4 5 6 blu giallo verde blu bianco arancione rosso 1 2 10 11 12 13 sed '2,4 s/bianco/blu/g' prova
<-- dalla 2a alla 4a riga sed '/.*ver.*/ s/bianco/blu/g' prova |
Problema:
Estrarre parti da un file cancellando intere righe
Note: la lettera 'd' indica la cancellazione. Cancellando
l'intero file tranne alcune righe, si ottiene il risultato di visualizzare le
righe volute. Con il secondo esempio si utilizza "-e" che consente di
specificare piu' comandi sed in sequenza, in questo caso due. Il primo toglie
tutte le righe che iniziano con "1" e il secondo toglie le righe vuote, che sono
quelle che iniziavano con "1". Si noti che la cancellazione ha la negazione che
si ottiene con "!d".
| sed '2,$ d' prova 1 2 3 4 5 6 sed -e 's/1.*//' -e '/^$/ d' prova blu giallo verde blu |
Problema:
Aggiungere linee e cambiare linee
Note: Con il comando "a" si aggiunge una riga a quella
successiva di un match. Con "i" si aggiunge una riga a quella precedente
il "match". Con "c" si sostituisce una linea.
| sed '/bianco/ a\la riga
precedente contiene bianco' prova 1 2 3 4 5 6 bianco giallo verde blu la riga precedente contiene bianco bianco arancione rosso la riga precedente contiene bianco 1 2 10 11 12 13 sed '/bianco/
i\la riga successiva contiene bianco' prova sed '/bianco/ c\questa riga
conteneva bianco' prova |
Problema:
Estrazione di una espressione regolare da un file
Note: con il backreference (vedi grep) possiamo estrarre una
espressione regolare da un file. Questo e' utile nel caso in cui ci siano parti
di un file variabili, ad esempio, perche' output di sistemi di visualizzazione
dati. Supponiamo di voler visualizzare cosa c'e' tra il numero 10 e il numero
12, immaginando che cio' che si trova tra questi due numeri non e' un dato fisso.
Ricordiamoci che le espressioni regolari oggetto di backreference devono essere
tra parentesi tonda. Per capire meglio il principo modifichiamo il file 'prova' file di input e
proponiamoci di estrarre il valore numerico di traffico in input:
|
Traffico in input: 244245 bytes |
| sed -e 's/.*input:
\([0-9]*\).*/\1/' -e '/output/ d' prova
244245 |
Awk
Abbiamo visto come con grep sia possibile estrarre righe ben precise da un file, con sed sia possibile effettuare modifiche in un file. Con awk e' possibile elaborare i dati in un file interpretandolo come una tabella. Consideriamo questo file di esempio:
| nome cognome citta' nascita marco privitera catania 1972 salvo giuffrida palermo 1980 daniele nauta messina 1985 santo micale catania 1960 |
Osservate il seguente comando:
| awk '/catania/
{if ($4>1960) print $1"-"$2" anno:
"$4}' prova marco-privitera anno: 1972 |
Con awk il file in tabella 4 viene interpretato come una tabella di database con spazio come separatore. Le varie colonne sono richiamabili tramite il comando '$'. La prima parte del comando, in rosso, e' un filtro sulla riga, opzionale. La parte in verde, anch'essa opzionale, rappresenta una condizione. In questo esempio cerchiamo in tabella i nomi di chi e' nato successivamente del 1972 a Catania. Come si vede ci sono delle similitudini con operazioni fatte con SQL in tabelle di database. In casi semplici, awk e' un ottimo strumento di analisi.
________________________________________________________________________________________
Applicazione ad Asterisk
_________________________________________________________________________________________________
Problema: Vogliamo filtrare l'output del comando "show channels" per interpretare lo stato delle linee (Zaptel)
Soluzione:
Interpretando l'output del comando "show channels" si deduce:
- Le chiamate entranti dall'esterno possiamo estrapolarle considerandon le
righe con Channel SIP e Application del tipo "bridged call Zap/NN"
- Le chiamate uscenti possiamo estrapolarle considerando le righe con
Channel SIP e Application del tipo Dial(Zap/g1...
| asterisk -rx "show channels" | grep -E "SIP.*Zap/[0-9]{1,2}.*" | sed 's/.*SIP\/\([0-9]\{2,3\}\).*Zap\/\([0-9]\{1,2\}\).*/\1 \2/' |
Analisi:
Il comando "show channels" restituisce un elenco delle conversazioni in corso e dei canali ad essi associati.
1. Consideriamo (grep) solo le righe
contenenti un canale sip (ad es. SIP/200) ed uno zaptel (ad es. Zap/24)
2. Preleviamo (sed) le espressioni regolari relative alla coppia data dal canale
sip (ad es.200) e quello zaptel (ad es. 24)
Note:
1. "sed" fa sostituzioni. Se in una riga
di un file non trova match lascia la riga inalterata. Per questo motivo e'
necessario che grep faccia trovare a sed solo righe che contengono entrambe le
espressioni regolari volute.
2. In questo esempio si presuppone che si adotti una numerazione SIP a 2 o 3
cifre e i canali zap siano ad 1 o 2 cifre.
3. Si ricorda che le parentesi graffe in una espressione regolare rappresentano
il numero di ripetizioni che puo' avere un pattern indicato in precedenza. In
questo esempio [0-9]{1,2} indica una o due cifre;
4. Si ricorda che \1 e \2 rappresentano il richiamo di una parte di espressione
regolare delimitata dalle parentesi tonde. Ad esempio ".*([0-9]{2}).*" permette
di tenere traccia di una coppia di numeri all'interno di una espressione piu'
complessa e di richiamarla successivamente utilizzando "\1";
5. L'espressione regolare va modificata per chiamate che non utilizzano Zaptel (chiamate
SIP<->SIP o SIP<->IAX per esempio)
6. Parentesi tonde e graffe vogliono il backslash. Anche il carattere slash vuole il backslash
Esempio:
| [root]# asterisk -rx "show
channels" Channel Location State Application(Data) SIP/504-08e89250 1018@agentsliv1:1 Up Bridged Call(Zap/61-1) Zap/61-1 s@macro-coda:12 Up Queue(codalivello1|t) Zap/2-1 (None) Up Bridged Call(SIP/500-b7411ab0) SIP/500-b7411ab0 06016605@ingresso: Up Dial(Zap/g1/6806685) SIP/511-08e4e290 1019@agentsliv1:1 Up Bridged Call(Zap/55-1) Zap/1-1 (None) Up Bridged Call(SIP/501-b740fd48) SIP/501-b740fd48 01788198@ingresso: Up Dial(Zap/g1/1786898) Zap/55-1 s@macro-coda:12 Up Queue(codalivello1|t) 8 active channels 4 active calls [root@ ~]# cat showchannels | grep -E "SIP.*Zap/[0-9]{1,2}.*" | sed 's/.*SIP\/\([0-9]\{2,3\}\).*Zap\/\([0-9]\{1,2\}\).*/\1 \2/' 504 61 511 55 |
Altro:
Nel caso in cui utilizziate il gruppo g1 per le chiamate uscenti potete
identificarle con questo comando:
|
grep -E "SIP.*Zap/g1.*" | sed 's/.*SIP\/\([0-9]\{2,3\}\).*Zap\/g1\/\([0-9]\{3,13\}\).*/\1 \2/' |
Per vedere semplicemente quali canali di tipo SIP sono in uso:
|
[root@ ~]# cat showchannels |
grep "SIP" | sed 's/.*\(SIP\/[0-9]\{2,3\}\).*/\1/' | uniq |
Notate il comando "uniq" che elimina eventuali righe duplicate
________________________________________________________________________________________
Script di trasferimento file tramite ftp previa verifica raggiungibilita' ICMP
_________________________________________________________________________________________________
Questo script bash e' stato utilizzato per
automatizzare il trasferimento file da un server linux a un sito ftp remoto
(sotto IIS 6.0 nel lab test). Particolarita' dello script e' la verifica della
raggiungibilita' IP del destinatario prima di procedere al trasferimento.
Lo script preleva un file di log (di asterisk nell'esempio),
lo rinomina includendone la data, e lo copia in un server remoto. E' un esempio
per fini didattici, va personalizzato se usato in esercizio.
#!/bin/sh
#by GF 2008
### VERIFICA RAGGIUNGIBILITA' ###
myHost="192.168.30.10"
count=$(ping -c 4 $myHost | grep 'received' | awk -F',' '{ print $2 }' | awk '{
print $1 }')
if [ $count -eq 0 ]; then
# 100% failed connettivita' assente
exit 0;
fi
### TRASFERIMENTO DATI ###
suffix=$(eval stat --printf=%z /var/log/asterisk/queue_log | awk
'{print $1}') #si prende la data dell'ultima modifica del file
nomeremoto=queue_log.$suffix
#genera un nuovo nome per il file queue, con la data inclusa
cp /var/log/asterisk/queue_log /var/log/asterisk/temp/$nomeremoto
# TRASFERIMENTO DATI SU SERVER
ftp -i -v -n 192.168.30.10 <<End-of-Session
user FTPUSERNAME FTPPASSWORD
lcd /var/log/asterisk/temp/
cd myfolder
cd mysubfolder
put $nomeremoto
bye
End-of-Session
exit 0
Copyright 2008 – Gianrico Fichera –
Questa pagina e' protetta dalla legge sul Diritto d'Autore. L’autore di questa pagina non si assume nessuna responsabilita’ e non da nessuna garanzia riguardante l’accuratezza e la completezza delle informazioni presenti nonche’ da conseguenze sull’uso delle informazioni presenti in questa pagina.
Pagina aggiornata il 15 Aprile 2009