Buongiorno a tutti. Oggi vi voglio parlare di come è fatto un processo. Potete immaginare un processo come una scatola nera o meglio ancora, per chi ha fatto un minimo di elettronica, come un tripolo (sennò cercate transistor su wikipedia).
Un processo nasce, cresce e muore con 3 stream “attaccati” ad esso:
–Stdin, anche noto come Standard Input, è lo stream da cui il processo legge gli input provenienti dall’ esterno, tipicamente dall’ utente che l’ha lanciato o da un altro programma.
–Stdout, anche noto come Standard Output, è lo stream di dati che un processo produce alla fine del suo job, volgarmente detto risultato.
–Stderr, anche noto come Standard Error è lo stream in cui il programma “vomita” eventuali codici d’errore a seguito di un comportamento inaspettato.
Perchè vi dico tutto questo? Il python nasce come glue, come colla, è infatti molto usato come collante tra vari programmi. Fortunatamente per noi esiste una tecnica nota come pipelining che permette di destinare lo stdout di un processo A come stdin di un altro processo, creano cosi vere e proprie pipeline (catene di montaggio). Chi ha familiarità con il mondo Unix non si stupirà delle mie parole. Un esempio?
cat /etc/pippo.txt | wc -l
Cosa abbiamo fatto? Abbiamo letto un file con cat e abbiamo mandato lo stdout di cat in input a wc, che ci ha calcolato il numero di linee del nostro file di testo. Ma ora veniamo al python.
Su Python-it.org si era intavolata una conversazione su come fosse possibile recuperare le informazioni da un file, ad esempio come da un file MP3 fosse possibile recuperare le ID3. L’utente Flame_Alchemist, che ringrazio, ha fatto osservare che tali info, qualora presenti, risiedono nei primi 128 byte del file Mp3.
Ecco allora l’idea: sfruttiamo un tool Unix chiamato hexdump (calma Linuxofili, funziona anche da voi 😀 ) che permette di fare il dump esadecimale di qualsiasi file e poi, col nostro amato Python, ci andiamo a recuperare le informazioni che vogliamo. E’ rozzo e probabilmente non lo userete mai, l’ho scritto solo per farvi vedere due cose:
-Come sia possibile gestire il pipeline in un programma python
-Uno studio di caso di come si realizza un banale parser a partire da un dump esadecimale.
import sys
import os
class Id3Parser:
def __init__(self):
self.input = str.split(str.rstrip(sys.stdin.read()),"\n")
def get_char_list(self):
'''Ritorna il dump cosi come e' stato preso in stdin, ogni carattere
rappresenta una cifra esadecimale'''
return self.input
def get_hex_list(self):
'''Permette di ottenere una lista con il valore decimale di tutti
i caratteri esadecimale presi da stdin'''
hex_list = [self.hexstr2ascii(el) for el in self.input]
return hex_list
def get_ascii_list(self):
'''Questa funzione preso un valore decimale ne trova il corrispettivo
valore ascii, comprimento la lista in modo che i caratteri non ascii
(minori di 32 in decimale) facciano da spaziatore tra un carattere
valido e l'altro'''
lst =[]
prev=0
for el in self.get_hex_list():
if el < 32 and prev < 32:
continue
elif el < 32 and prev > 32:
lst.append("00")
else:
lst.append(chr(el))
prev = el
return lst
def hexstr2ascii(self, value):
'''Questa funzione, preso un qualsiasi valore ascii rappresentante un
esadecimale (es. '4B') ne trova il corrispettivo valore decimale.'''
symbol_dict={'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,
'6':6,'7':7,'8':8,'9':9,
'A':10,'B':11,'C':12,'D':13,'E':14,'F':15}
fst_hex = symbol_dict[value[0]]
snd_hex = symbol_dict[value[1]]
return (fst_hex*16 + snd_hex)
def get_info_list(self):
'''Questa funzione ritorna una lista delle informazioni sensibili.'''
lst=[]
info=""
for el in self.get_ascii_list():
if (el == "00"):
lst.append(info)
info=""
continue
else:
info+=el
return lst
if __name__ == "__main__":
from id3parser import Id3Parser
parser = Id3Parser()
print parser.get_info_list()
COME SI USA:
Da shell:
$ hexdump -n 128 -v -e ‘1/1 “%02X” “\n”‘ <nome_file> | python id3parser.py
dove al posto di nome_file dovete mettere il titolo della canzone.
NOTA: Poichè il blog converte gli apici e i doppi apici in backquote, vi invito a riscrivervi tali apici se copiate ed incollate il codice nella shell, altrimenti non funziona (ringrazio Eugenio per la segnalazione).
Ci sono altri n-mila modi di farlo, mi interessava farlo così per farvi vedere come python sia un valido collante tra processi applicativi.
Vi allego come sempre il codice, alla prossima!
Alfredo Di Napoli
Codice: id3parser.py