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.
Trackback
[…] 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, […]