giovedì 17 ottobre 2013

BASH - Guida all'automazione: Attendere l'avvio di XFCE.

Stavolta siamo alle prese con un problema di precedenza: conky, il noto monitor di sistema grafico, viene lanciato in "autostart" da Xfce con i parametri che aveva nella sessione precedente; a volte però capita che impieghi meno tempo ad avviarsi del desktop, non riuscendo così ad agganciarsi alla "finestra desktop" per poterci disegnare.

Dobbiamo perciò fare in modo che conky si avvii solo dopo che il desktop si è avviato.

Armati del nostro fidato editor di testo, andiamo a buttar giù uno script che ci permetta di ottenere questo comportamento.

Passo 1: Riconoscere l'obiettivo

Il comportamento che ci interessa ottenere, è il seguente:
All'avvio dell'ambiente grafico, conky deve essere visibile sullo sfondo del desktop.

Passo 2: Identificazione del problema

Raccogliamo informazioni sul problema:
1) A meno che non "blocchiamo" la sessione, oppure che non chiudiamo conky prima di spegnere il computer, xfce si salverà i parametri con cui sta girando allo spegnimento e lo lancerà allo stesso modo all'avvio successivo.
2) Dobbiamo attendere che il desktop sia effettivamente visibile prima di lanciare conky con i giusti parametri.

L'identificazione stavolta è piuttosto semplice, la procedura che dovremo seguire, siccome non sarebbe pratico dover chiudere conky prima di spegnere il computer, sarà divisa in due punti:
Prima termineremo ogni istanza di conky, per rimuovere quelle che xfce lancia comunque, poi attenderemo che xfdesktop sia avviato, dopodichè avvieremo le nostre istanze con i giusti parametri.

Passo 3: Creazione dell'automazione

Il file che andiamo a creare stavolta per la nostra automazione, l'ho chiamato, in una esplosione di fantasia, startconky; come al solito ci scriveremo per prima la riga di "intestazione", per chiarire al sistema quale interprete ci interessa che esegua il nostro script:
#!/bin/bash
Abbiamo già visto la volta scorsa a cosa serve questa riga, d'ora in avanti cercherò di evitare di tediarvi scrivendola a parte.
Dovremo fare in modo che il nostro script chiuda le istanze di conky già aperte, e lo faremo inviandogli in massa un segnale di terminazione, con lo strumento killall:
#!/bin/bash
killall -9 conky
Il parametro "-9" indica il segnale da inviare, che in questo caso è corrispondente a SIGKILL, per terminare i processi che hanno come nome "conky". Successivamente, dovremo metterci in attesa di xfdesktop, che è il gestore del desktop di xfce, per essere sicuri che sia avviato prima di lanciare di nuovo conky.
while [ -z "$(ps aux | grep xfdesktop | grep -v "grep")" ]; do
 sleep 0.2;
done;
Analizziamo la riga da vicino, suddividendola come la volta scorsa:
while  [ -z  $(  ps aux | grep 'xfdesktop' | grep -v 'grep'  )  ] ;  do 
    sleep 0.2 ;
done ;
Vediamo cosa significano questi comandi uno per uno:
while CONDIZIONE  do BLOCCO  done
Questo è un ciclo di esecuzione, chiamato "ciclo while":
Esegue BLOCCO, che sarà un blocco di istruzioni, ripetutamente, se CONDIZIONE risulta VERA; un po' come il test if della volta scorsa, solo che il ciclo ripete l'esecuzione.
[ TEST ] ;
La volta scorsa abbiamo tralasciato questa parte, poichè inserita in un contesto specifico, stavolta la consideriamo un po' di più.
Bash ha un comando interno che esegue i test, rappresentato dalle parentesi quadre, questo blocco di codice funziona con degli speciali "switch", la volta scorsa abbiamo usato lo switch -z, per verificare se il parametro fosse "vuoto", e pure stavolta faremo lo stesso, ma ci sono molti altri switch utilizzabili, e può anche gestire verifiche più complesse, per il momento però basti sapere che è a tutti gli effetti una "istruzione" per Bash, e per questo è molto importante il ";" dopo, poichè la parte successiva al test è un'altra istruzione, quindi bisogna separarle.
$( BLOCCO )
Abbiamo già visto a cosa serve questa parte, esegue banalmente il blocco di istruzioni, riportandone il risultato, che in questo caso ci serve per effettuare il test.
ps aux | grep 'xfdesktop' | grep -v 'grep'
Eccoci alla parte "divertente" del codice, che altro non è che la stessa lista della volta scorsa, solo che stavolta ci facciamo filtrare il processo "xfdesktop". Ricapitolando, questo comando ritornerà una stringa vuota se il processo xfdesktop non è attivo, la riga coi suoi dettagli se invece è attivo.

L'intero blocco esegue e filtra la lista di processi, individuando solo quelli che si chiamano "xfdesktop", nel caso in cui esso non sia presente (stringa vuota), il test -z ritornerà un valore TRUE (è vuoto), facendo si che il ciclo while continui l'esecuzione del blocco fra do e done.
Quindi il ciclo ripeterà il blocco di istruzioni solo quando xfdesktop non si trova, e smetterà quando invece il processo comparirà nella lista.
Il blocco di istruzioni nel nostro caso è molto semplice, visto che ci dobbiamo limitare ad attendere che il desktop sia avviato, mettiamo un ritardo (sleep) come unica istruzione, solo per evitare che il nostro ciclo occupi interamente il computer e lo rallenti troppo.
Il valore del ritardo è espresso in secondi, e lo 0.2 (due decimi di secondo) che ho impostato valgono perfettamente per il mio computer, in quanto il loop viene eseguito da 1 a 3 volte a seconda dello stato della macchina.
Ricordo che il ritardo in questione è inteso da quando xfce4-session lancia i comandi in autostart, a quando xfdesktop viene caricato, ed essendo il primo processo lanciato da xfce4-session, questo script non dovrebbe essere nemmeno necessario, ma si sa che l'informatica non è una scienza esatta, e capita che workaround come questo siano necessari.

Adesso manca soltanto da lanciare il nostro conky con i suoi parametri, quindi potrebbe essere sufficiente una riga per completare il nostro script:
#!/bin/bash
while [ "$(ps aux | grep xfdesktop | grep -v "grep")" == "" ]; do
 sleep 0.2;
done;
killall -9 conky
conky -c ${HOME}/.conky/top-left.rc
Solo che io sono un maniaco della personalizzazione, e mi capita spesso di modificare la configurazione di conky, lanciandone anche più istanze, per gestire diverse posizioni dello schermo, quindi ho uno script di lancio un po' più complesso:
#!/bin/bash
while [ "$(ps aux | grep xfdesktop | grep -v "grep")" == "" ]; do
 sleep 0.2;
done;
killall -9 conky
rm -f ${HOME}/.conky/cache/*
if [ -e "${HOME}/.conky/top-left.rc" ]; then
 conky -c ${HOME}/.conky/top-left.rc
fi
if [ -e "$HOME/.conky/bottom-left.rc" ]; then
 conky -c ${HOME}/.conky/bottom-left.rc
fi
if [ -e "$HOME/.conky/top-right.rc" ]; then
 conky -c ${HOME}/.conky/top-right.rc
fi
if [ -e "$HOME/.conky/bottom-right.rc" ]; then
 conky -c ${HOME}/.conky/bottom-right.rc
fi
Le parti nuove sono piuttosto rapide da spiegare:
Premetto che tengo tutto quello che riguarda conky, o meglio l'attuale configurazione di conky nella directory .conky della mia home.
rm -f ${HOME}/.conky/cache/*
Non credo ci sia da spiegare questo comando, svuota la directory .conky/cache, che alcuni dei miei script di monitor usano per non caricare troppo la CPU, e vanificare il fatto di avere un monitor di sistema.
if [ -e "${HOME}/.conky/top-left.rc" ]; then
 conky -c ${HOME}/.conky/top-left.rc
fi
Questa è una variazione del normale test con if, come si può vedere, il test è composto allo stesso modo degli altri, solo che stavolta usa lo switch "-e", che controlla se il file che gli passiamo come argomento esiste o no, ritornando TRUE se esiste.
Se il file esiste (il test ritorna TRUE), if eseguirà la porzione di codice fra then e fi, che non fa altro che lanciare conky passando come file di configurazione il file di cui abbiamo appena verificato l'esistenza.
Il resto dello script non è altro che una reiterazione di controlli e conseguenti lanci per i quattro files che sono abituato ad utilizzare per i miei setup di conky, con questo script mi basta sostituire la directory .conky per cambiare il "tema" del mio monitor di sistema.