Posts Tagged ‘ UNIX

Unix Guide

Spesso quando ci si trova a dover utilizzare più sistemi operativi diversi, benché della famiglia UNIX, capita di confondere i comandi, o di non ricordasi alcune strutture particolari di un sistema rispetto ad un altro, per esempio il nome della variabile LD_LIBRARY_PATH è diverso su AIX, sul quale è LIBPATH, mentre su HP-UX è SHLIB_PATH…

Molto spesso questo sito (http://unixguide.net) mi è utile per trovare il comando che non ricordo mentre uso il sistema. Sebbene qua e là ci sia qualche inesattezza e qualcosa che è stato aggiornato nel tempo, trovo questa tabella molto utile e la consiglio a tutti coloro che ogni tanto hanno il vuoto di memoria come me :)

Di seguito il link diretto alla versione PDF

Aggiungere il timestamp ad ogni riga in output

Eccomi di ritorno! È passato un po’ di tempo dall’ultimo post, un po’ per impegni vari, un po’ per pigrizia ed un po’ per i tempi di attivazione del dominio (fabiofalcinelli.it). Come va? Come state? :)

Vi descrivo di cosa avevo bisogno e di come ho risolto. Supponiamo di avere un programma che generi output, ma che questo output sia sprovvisto di timestamp. Se il programma deve essere eseguito ad intervalli regolari diventa un po’ difficile capire cosa sta succedendo analizzandone l’output che ne è stato eventualmente redirezionato su un file.

Se invece di redirezionarlo direttamente al file, lo diamo prima in pasto ad awk sarà però possibile aggiungere, per ogni riga, il timestamp di generazione della riga stessa. Ecco di seguito come, utilizzando il tool svnsync come esempio:

svnsync synchronize svn://127.0.0.1:8081 | nawk '{
"date \"+%a %b %d %Y %H:%M:%S -\"" |
getline systemDate;
close ("date \"+%a %b %d %Y %H:%M:%S -\"") ;
print systemDate, $O;
}'
>> svnsync.log

In realtà ho utilizzato nawk la cui implementazione supporta alcune funzionalità in più. Non ci dovrebbero essere problemi usando la stessa procedura con gawk.

Come al solito, spero che possa essere d’aiuto a qualcuno facendogli risparmiare qualche minuto del suo tempo :)

Java – Esecuzione comandi su CLI parte II

Se vi ricordate di un pezzo di codice scritto da me e che funzionava particolarmente bene per invocare comandi su UNIX… Beh… Scordatevelo! O meglio, dovrete fare qualche piccola modifica.

Il codice in questione sembra, infatti, causare un piccolo problema chiamato deadlock.

La cosa non si presenta sempre, ma dipende fortemente dalla quantità di output che genera il comando e da come il sistema operativo gestisce il buffering della system call “write”. Lanciando truss da dentro al codice java, infatti, notavo che l’esecuzione delle system call si bloccava in attesa:

ioctl(1, TCGETA, 0xFFBEDF34) Err#22 EINVAL
fstat64(1, 0xFFBEDFA8) = 0
brk(0x00068A70) = 0
brk(0x0006AA70) = 0
write(1, " D A T A ".., 5120) = 5120
write(1, " * - > *".., 5120) = 5120
llseek(0, 0, SEEK_CUR) Err#29 ESPIPE
write(1, " * - > * * * * * ".., 635) (sleeping...)

Non è stato facilissimo arrivare alla causa, il metodo è infatti molto semplice, ma adesso che ho identificato il problema l’errore appare quasi evidente. Il problema risiede infatti nel canale di standard error letto prima dello standard output:

  1. Prima di poter leggere lo standard error è necessario che il processo che esegue il comando termini, e non è detto che vi siano errori;
  2. Prima di poter avere tutto l’output disponibile c’è bisogno di qualcuno che consumi i dati nel buffer, ma quel qualcuno è in attesa sullo standard error;
  3. Deadlock!

Sinceramente, questa spiegazione, seppur sensata non mi convince ancora appieno e appena avrò più tempo analizzerò meglio i trace delle system call, nonostante ciò riporto di seguito la versione del metodo che risolve il problema.

public static String execCommand(String cmd) throws IOException{
String result = null;
String temp = null;
BufferedReader stdout = null;
BufferedReader stderr = null;

Process proc = Runtime.getRuntime().exec(cmd);

/*consume the output*/
stdout = new BufferedReader(new InputStreamReader(
proc.getInputStream()));
temp = stdout.readLine();

while(temp!=null){
if(result==null)
result = temp+”\n”;
else
result += temp+”\n”;
temp = stdout.readLine();
}

stdout.close();

/*check if errors occurred*/
stderr = new BufferedReader(new InputStreamReader(
proc.getErrorStream()));
temp = stderr.readLine();

if(temp!=null){
result = temp+”\n”;
temp = stderr.readLine();
while(temp!=null){
result += temp+”\n”;
temp = stderr.readLine();
}

stderr.close();
throw new IOException(result);
}

stderr.close();
/*if no exceptions occurred then proceed to return the output*/
return result;
}

Questo è quanto, il metodo main d’esempio del post precedente però è ancora valido :)

Java – Esecuzione comandi su CLI

Prima o poi può essere utile astrarre un po’ meno dalla macchina e tornare a interfacciarsi con il Sistema Operativo sottostante. Quello che può tornare utile è quindi un metodo per eseguire comandi di sistema dalla VirtualMachine Java. Il seguente è un metodo che ho scritto in fretta e furia, ma che su sistemi UNIX sembra funzionare molto molto bene:

public static String execCommand(String cmd) throws IOException{
   String result = null;
   BufferedReader stdout = null;
   BufferedReader stderr = null;
   Runtime runtime = null;
   Process proc = null;

   runtime = Runtime.getRuntime();
   proc = runtime.exec(cmd);
   stderr = new BufferedReader(new InputStreamReader(
                                          proc.getErrorStream()));
   String temp = stderr.readLine();

   /*check if errors occurred*/
   if(temp!=null){
      do{
         if(result==null)
            result = temp+"\n";
         else
            result += temp+"\n";

         temp = stderr.readLine();
      }while(temp!=null);

      stderr.close();
      throw new IOException(result);
   }

   /*if no exceptions occurred then proceed to return the output*/
   stdout = new BufferedReader(new InputStreamReader(
                                           proc.getInputStream()));
   temp = stdout.readLine();

   while(temp!=null){
      if(result==null)
         result = temp+"\n";
      else
         result += temp+"\n";
      temp = stdout.readLine();
  }

  stdout.close();
  return result;
}

L’idea è semplice: se il comando fallisce, restituisco l’esito del comando (lo standard error) come un’eccezione di I/O, altrimenti il metodo torna l’esito del comando (lo standard output).

A questo punto possiamo, per esempio, scrivere il seguente main, un po’ inutile, ma rende l’idea

public static void main(String args[]){
   try{
      String result = execCommand("ls -lrt");
      System.out.println(result);
   }catch(IOException e){
      System.err.println(e.getMessage());
   }
}

Ovviamente il codice non è ottimizzato essendo la prima stesura di getto, alcune cose potevano essere evitate (i due BufferedReader per esempio), ma spero che a qualcuno questo metodo torni utile.