Alessio Biancalana Grab The Blaster di Alessio Biancalana

File di testo e righe duplicate, eliminiamole.

Oggi nel tardo pomeriggio, il mio amico @chemicky_pes ha fatto una domanda su Twitter il cui scopo per certi versi può risultare inutile, tuttavia per puro scopo di ricerca abbiamo pensato di studiare un po' la cosa e risolvere questo piccolo quesito, in vari modi; non masticando lui la Bash, e volendo affrontare il problema con un software in C, io ho tagliato corto con un po' di alto livello che, in questi casi, ci salva sempre :D

[blackbirdpie id="3153761987989504"]

In particolare la questione, non ben spiegata con quel twit, è stata: e se io non volessi doppioni nel .bash_history? Il .bash_history, per chi non sapesse, è quel file nascosto nella home di un utente in un sistema operativo Unix, che governa la "memoria" della console; ossia, premendo il tasto SU (si, la freccia), si accede agli ultimi comandi in ordine cronologico che sono stati inseriti, e l'elenco è contenuto proprio nel suddetto file. Ora, volendo risolvere il problema, ho approcciato la cosa preferendo un po' di sano scripting. Ed ho risolto con uno script di cui vi posto lo pseudocodice, chè se leggete il mio codice Bash fate notte e vi viene il mal di testa :P

for rigazero to ultimariga do{ #indice X
for rigazero to ultimariga do{ #indice Y
if (rigax==rigay)
cancella_riga
}}

In pratica che succede: grazie al doppio for scorro il file di riga in riga e cancello quelle duplicate. Problema: comunque mi cambiano parecchi parametri se elimino la riga in maniera netta, devo mantenere lo spazio vuoto al suo posto, o usare un while. Siccome non sono una persona molto paziente, ho cercato su Google una maniera rapida per risolvere il problema delle righe duplicate, e ho trovato delle dritte su AWK, praticamente a mia opinione l'unico programma su Linux più difficile da usare di Sed: infatti AWK è un programma che accetta non parametri, bensì vere e proprie istruzioni come input. Un programma programmabile, praticamente l'inferno. Non so che succede se lo si usa in maniera ricorsiva, probabilmente escono le cavallette dal PC, o gli UFO vengono a rapirti. Fatto sta che con una bella istruzione, a occhio banale, di AWK, ho risolto:

awk '!x[$0]++' targetfile.txt

A occhio, dicevo, è banale, ma spiegare perchè una riga del genere elimini le righe duplicate in un file... :D

Non entrando nei dettagli, AWK con quel parametro scannerizza il file come un array che in ogni cella ha una riga. Dopodichè grazie al suo mistico potere (secondo me infatti sto software funziona per magia) guarda quali sono le righe duplicate, e agisce di conseguenza, mandando in output il file senza doppioni. Usarlo in pratica è un altro conto, ed è leggermente più complicato, perchè necessita di un file temporaneo a cui appoggiarsi:

awk '!x[$0]++' filetarget.txt > temp.txt && mv -f temp.txt filetarget.txt

In questa maniera facciamo fare ad AWK il suo porco lavoro, poi sbattiamo tutto nel temp.txt, dopodichè facciamo la copia forzata sul file target. Et voilà :)

Ovviamente però, la soluzione è ancora più semplice. Infatti Bash ha una maledetta opzione per fare tutto ciò, e ce l'ha detta @axsergi (il compagno di merende con cui mi scambio tipsntricks vari, perchè siamo entrambi AUR packager per Arch Linux): basta infatti aggiornare una maledetta variabile d'ambiente che dice alla console proprio questo :D

export HISTCONTROL=ignoredups

Tuttavia la teoria spiegata è comunque valida: questo ragionamento fatto con AWK può applicarsi a qualunque file, e magari ricordare questo comando quando abbiamo bisogno di sfoltire un file troppo corposo che ci da fastidio su un server può risparmiarci un po' di grattacapi ;)

comments powered by Disqus

Member of

Previous Random Next