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

@GianguidoSora aspè prima di tutto. il terminale nel tuo Arch ricorda i comandi anche i doppioni?

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 ;)

Post correlati:

This entry was posted in Linux and tagged , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.
  • http://www.google.com/profiles/federico.granata Edo

    ovviamente dipende dal contenuto del file ma un bel
    sort | uniq
    fa sempre il suo sporco lavoro ;)

  • http://dottorblaster.it/ Bl@ster

    Verissimo, ho dimenticato di inserirlo :D
    Però in rari casi in cui ti interessa che l’ordine delle righe rimanga precisamente quello, sort te lo rovina un po’ :P

  • Anonymous

    Farlo con sed è ancora più sadico di awk :D

  • http://andrealazzarotto.com/ Lazza

    Si può fare in modo che elimini i doppioni “per primi” e non “per secondi”? In modo che mi tenga i comandi doppi che ho usato solo quando li ho usati per ultimi? :P

  • http://dottorblaster.it/ Bl@ster

    la variabile d’ambiente che configura Bash scritta lì dovrebbe farlo, in teoria.
    Non ho testato la cosa :D

  • juhan

    Ottimo post. Io awk quando lo usavo tiravo giù tutti i santi del calendario.
    Esiste sul web un sito ottimo, dove non manca una guida a awk http://www.thegeekstuff.com/2010/01/awk-introduction-tutorial-7-awk-print-examples/ (questo è uno della serie).
    Con Ubuntu avevo avuto problemi con ignoredups, non so se per errori miei.
    OT: MM continua a avere problemi con wmctrl, non identifica l’area di lavoro. Nessuno ne sa qualcosa?

  • http://dottorblaster.it/ Bl@ster

    Mi sa di strumento troppo potente, comunque è spettacolare :D
    Grazie dell’indirizzo per le guide, è utilissimo e credo che ne farò uso :P

    Riguardo WMCTRL, non so dirti. Qua sembrano diventare tutti scemi appresso al look’n feel e poi ci si perde i pezzi ;)

  • http://mrmodd.it/ MrModd

    Ricorda la domanda fondamentale: “Ma si può fare di meglio???”

    A parte tutto bellissimo articolo. Non sarebbe male metterlo in cron per fargli fare una pulizia automatica di tanto in tanto.
    ignoredups? Troppo da nabbi :D

  • http://www.google.com/profiles/federico.granata Edo

    quindi tu avresti dei file di testo in cui l’ordine delle righe è importante ma ciò nonostante potresti avere delle righe non consecutive tra di loro ?
    potresti farmi un esempio, mi sa che sono casi così rari che non mi vengono in mente …

  • http://dottorblaster.it/ Bl@ster

    Fare ingegneria ti fotte il cervello :D
    Caso pratico: proprio il bash_history.
    Se vai di sort | uniq prima ti viene fatto il sort di tutto il file, quindi vengono ordinate tutte le righe, e l’ordine temporale viene stravolto. È chiaro che è da paranoico, ma il giorno che poi sort | uniq per un malaugurato caso ti uccide qualcosa, poi è il caso di sapere che cosa è successo :D

  • http://dottorblaster.it/ Bl@ster

    È per quello che ho postato tre soluzioni, anche se le sette soluzioni a fibonacci non le batte nessuno :D

  • http://www.google.com/profiles/federico.granata Edo

    sarà che con il trasloco in atto mi ritrovo senza energie ma non riesco a seguirti …
    a parte che nella history puoi salvarti anche la data in qui un dato comando è stato lanciato …
    se tu cancelli dei comandi dalla history, qualsiasi mezzo tu utilizzi, non potrai aspettarti di poter ricostruire quanto avvenuto …

  • http://mrmodd.it/ MrModd

    Ahahahahah!!!