Python – Catturare i messaggi di xdg-open e di os.system()

In un post precedente ho raccontato di come far eseguire comandi a un pulsante, usando xdg-open. C’è il problema che eventuali messaggi di errore restituiti dal programma che si vuole lanciare o dalla shell stessa si perdono, a meno che non si tenga il terminale aperto, caso molto improbabile.

Ma una delle cose che rendono *nix e Linux meravigliose è che (quasi) tutto è possibile (o quasi).
Bastano un po’ di googlate e il web ci fornisce, se non la soluzione pronta, almeno l’indicazione della via da seguire. A prova di me.
Sono partito da questa pagina http://effbot.org/pyfaq/how-do-i-run-a-subprocess-with-pipes-connected-to-both-input-and-output.htm e il risultato è questo:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import tempfile
import os

def xexec(command):
	stout = ""
	sterr = ""
	outfile = tempfile.mktemp()
	errfile = tempfile.mktemp()
	command = "( %s ) > %s 2> %s" %(command, outfile, errfile)

	errorlevel = os.system(command) >> 8
	stout=open(outfile, "r").read()
	os.remove(outfile)
	sterr = open(errfile, "r").read()
	os.remove(errfile)
	return [errorlevel, stout, sterr]

lista_cmds = ['xdg-open http://www.google.com',
              'xdg-open zhttp://www.google.com',
              'xdg-open immagine.jpg',
              'xdg-open manca.jpg',
              'xdg-open manuale.pdf',
              'firefox http://www.google.com',
              'firefox zhttp://www.google.com',
              'zfirefox http://www.google.com',
              'xdg-open firefox http://www.google.com',
              'xdg-open "firefox http://www.google.com"']

n = 0
for cmd in lista_cmds:
	res = xexec(cmd)
	n += 1
	print n
	print "cmd =", cmd
	print "errorlevel:", res[0]
	print "stdout:", res[1]
	print "stderr:", res[2]
	print

Semplice vero?
Solo due note:
La funzione l’ho chiamata xexec() perché ho i miei limiti, pensate che continui a valere l’aurea regola dei nomi significativi e poi, dai, io ho iniziato con il Fortran!
L’espressione >> 8 della riga 14 è equivalente a / 256 (28). Lo so, lo so che lo sanno tutti: la nota è un promemoria personale per me medesimo 😀

Supponendo che lo script si chiami pwp3.py (sempre a proposito dei nomi significativi) e nella directory cartella ci siano i file manuale.pdf e immagine.jpg ecco quello che si ottiene:


* : /media/algol/lab/OKp/cap-oe $ python pwp3.py
1
cmd = xdg-open http://www.google.com
errorlevel: 0
stdout:
stderr: 

2
cmd = xdg-open zhttp://www.google.com
errorlevel: 4
stdout:
stderr: Errore nel mostrare l'URL: La posizione specificata non è supportata

3
cmd = xdg-open immagine.jpg
errorlevel: 0
stdout:
stderr: 

4
cmd = xdg-open manca.jpg
errorlevel: 4
stdout:
stderr: Errore nel mostrare l'URL: Errore nell'eseguire lo stat del file
"/media/algol/lab/OKp/cap-oe/manca.jpg": Nessun file o directory

5
cmd = xdg-open manuale.pdf
errorlevel: 0
stdout:
stderr: 

6
cmd = firefox http://www.google.com
errorlevel: 0
stdout:
stderr: 

7
cmd = firefox zhttp://www.google.com
errorlevel: 0
stdout:
stderr: 

8
cmd = zfirefox http://www.google.com
errorlevel: 127
stdout:
stderr: sh: zfirefox: not found

9
cmd = xdg-open firefox http://www.google.com
errorlevel: 1
stdout:
stderr: xdg-open: unexpected argument 'http://www.google.com'
Try 'xdg-open --help' for more information.

10
cmd = xdg-open "firefox http://www.google.com"
errorlevel: 4
stdout:
stderr: Errore nel mostrare l'URL: Errore nell'eseguire lo stat del file
"/media/algol/lab/OKp/cap-oe/firefox http:/www.google.com": Nessun
file o directory

Sembra funzionare 🙂 Intanto vediamo che lo standard output è sempre vuoto e i messaggi di errore sullo standard error sono intercettati. E il codice di errore ritornato è corretto.

Nel caso numero 7 l’errore viene rilevato da firefox perché per la shell il comando è corretto, a differenza del successivo caso #8.

Naturalmente la xexec() non accetta le ridondanze come nei casi 9 e 10.

Una nota: chiamate successive a firefox in tempi brevissimi possono generare questo errore:

Firefox is already running, but is not responding. To open a new window,
you must first close the existing Firefox process, or restart your system.

Il rimedio potrebbe essere di inserire time sulla nei moduli importati (righe 4 o 5) e fare una chiamata a sleep() dopo l’ultima istruzione; vale a dire aggiungere una riga (la 42) così formata time.sleep(10) dove il 10 significa 10 secondi.

Posta un commento o usa questo indirizzo per il trackback.

Trackback

  • lcm – J (e Python) | Ok, panico su 19 marzo 2013 alle 09:27

    […] esempio Python. Cerrrto usando la pipe. Avevo già trattato questo argomento nell’antichità, qui ma avevo usato funzioni che adesso sono deprecate e poi si può fare più brevemente, […]

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.

%d blogger hanno fatto clic su Mi Piace per questo: