<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Awk on Melabit</title>
    <link>https://melabit.com/it/tags/awk/</link>
    <description>Recent content in Awk on Melabit</description>
    <generator>Hugo</generator>
    <language>it</language>
    <lastBuildDate>Tue, 01 Dec 2020 06:00:00 +0000</lastBuildDate>
    <atom:link href="https://melabit.com/it/tags/awk/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Il CNR è anche questo: un po&#39; di codice</title>
      <link>https://melabit.com/it/2020/12/01/il-cnr-e-anche-questo-un-po-di-codice/</link>
      <pubDate>Tue, 01 Dec 2020 06:00:00 +0000</pubDate>
      <guid>https://melabit.com/it/2020/12/01/il-cnr-e-anche-questo-un-po-di-codice/</guid>
      <description>&lt;img src=&#34;https://imgs.xkcd.com/comics/good_code.png&#34; alt=&#34;&#34; title=&#34;XKCD, Good code&#34;&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;em&gt;XKCD, &lt;a href=&#34;https://xkcd.com/844/&#34;&gt;Good code&lt;/a&gt;&lt;/em&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Per concludere nel miglior modo possibile questa serie di articoli (qui la &lt;a href=&#34;https://melabit.wordpress.com/2020/10/25/il-cnr-e-anche-questo-concorsi-senza-frontiere/&#34;&gt;prima&lt;/a&gt; e la &lt;a href=&#34;https://melabit.wordpress.com/2020/11/08/il-cnr-e-anche-questo-concorsi-in-latex/&#34;&gt;seconda&lt;/a&gt; parte), cosa ci può essere di meglio di un po&amp;rsquo; di codice?&lt;/p&gt;&#xA;&lt;h4 id=&#34;estrarre-il-testo-da-un-file-pdf&#34;&gt;Estrarre il testo da un file PDF&lt;/h4&gt;&#xA;&lt;p&gt;Cominciamo dallo script in R, &lt;code&gt;pdf2csv.R&lt;/code&gt;, che estrae il testo da un file PDF, (che in questo caso specifico ho usato per &lt;a href=&#34;https://melabit.wordpress.com/2020/11/08/il-cnr-e-anche-questo-concorsi-in-latex/&#34;&gt;estrarre i dati&lt;/a&gt; dalla domanda di partecipazione ad un concorso precedente). Qui sotto trovate l&amp;rsquo;immagine dello script, realizzata con &lt;a href=&#34;https://carbon.now.sh/&#34;&gt;Carbon&lt;/a&gt; (perché così è molto più bello), su GitHub c&amp;rsquo;è il &lt;a href=&#34;https://github.com/sabinomaggi/melabit/tree/main/un-po-di-codice&#34;&gt;sorgente vero e proprio&lt;/a&gt;, per chi voglia provare ad usarlo.&lt;/p&gt;&#xA;&lt;img src=&#34;https://melabit.files.wordpress.com/2020/11/pdf2csv-1.png&#34; alt=&#34;&#34;&gt;&lt;p&gt;Per eseguire lo script è necessario aver installato sul proprio computer,  non importa se è un Mac o un PC con Linux o Windows, &lt;a href=&#34;https://www.r-project.org/&#34;&gt;l&amp;rsquo;ambiente R&lt;/a&gt; (in questo momento è disponibile la versione 4.0.3), meglio ancora se accompagnato da &lt;a href=&#34;https://rstudio.com/products/rstudio/&#34;&gt;RStudio Desktop&lt;/a&gt;, che è di gran lunga il migliore sistema integrato di sviluppo (IDE) che abbia mai usato, oltre che uno strumento efficacissimo per affacciarsi all&amp;rsquo;uso di R.&lt;/p&gt;&#xA;&lt;p&gt;Il codice è molto semplificato, ho tolto tutto ciò che non è strettamente necessario a far funzionare lo script. La chiave di tutto è la libreria &lt;a href=&#34;https://cran.r-project.org/web/packages/pdftools/index.html&#34;&gt;pdftools&lt;/a&gt; per R.  Di librerie per estrarre dati dai file PDF ne ho provate moltissime, sia per R che per Python, ma &lt;code&gt;pdftools&lt;/code&gt; le batte tutte per potenza, semplicità e velocità. Ci sono dei &lt;em&gt;tool&lt;/em&gt; che convertono un PDF in testo al ritmo di una pagina al minuto, &lt;code&gt;pdftools&lt;/code&gt; riesce a convertire (molto bene, peraltro) un file di 400 pagine &lt;a href=&#34;https://www.snpambiente.it/2018/02/24/rapporto-controlli-ambientali-del-snpa-aia-seveso-edizione-2017/&#34;&gt;come questo&lt;/a&gt; in appena 5-6 secondi. C&amp;rsquo;è altro da aggiungere?&lt;/p&gt;&#xA;&lt;p&gt;Lo script può essere utilizzato dalla linea di comando (per capirci, dal Terminale), lasciandolo esattamente com&amp;rsquo;è ed eseguendo il comando &lt;code&gt;pdf2csv.R&lt;/code&gt; seguito dal nome dal file da convertire (se il nome del file contiene degli spazi va scritto fra virgolette),&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#x9;./pdf2csv.R file-da-convertire.pdf&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;che produrrà due file &lt;code&gt;.csv&lt;/code&gt; contenenti il testo estratto dal file PDF. Il primo, con lo stesso nome del file di partenza, ha le righe numerate e cerca di riprodurre per quanto è possibile il &lt;em&gt;layout&lt;/em&gt; del file originale. Nel secondo, salvato con il suffisso &lt;code&gt;-clean&lt;/code&gt;, mancano i numeri di linea e vengono rimossi tutti gli spazi in eccesso, rendendolo più adatto ad una analisi automatica, in particolare quando il testo si estende per tutta la pagina (il primo file, invece, è molto più utile quando il testo è organizzato in colonne).&lt;/p&gt;&#xA;&lt;p&gt;Prima di usare per la prima volta &lt;code&gt;pdf2csv.R&lt;/code&gt; bisogna renderlo eseguibile tramite il comando &lt;code&gt;chmod&lt;/code&gt; (ne ho già scritto diffusamente &lt;a href=&#34;https://melabit.wordpress.com/2018/12/30/script-per-tutti-i-giorni-shell-e-parametri/&#34;&gt;qui&lt;/a&gt;).&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#x9;chmod u+x pdf2csv.R&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In alternativa si può lanciare lo script tramite il comando &lt;code&gt;Rscript&lt;/code&gt; installato con R, senza che sia necessario renderlo eseguibile.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#x9;Rscript ./pdf2csv.R file-da-convertire.pdf&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;È preferibile che il file PDF da convertire si trovi nella stessa cartella di &lt;code&gt;pdf2csv.R&lt;/code&gt;. In caso contrario il testo estratto viene comunque salvato nella cartella dove si trova la script (ve l&amp;rsquo;avevo detto che lo script era molto semplificato!).&lt;/p&gt;&#xA;&lt;p&gt;Per eseguire &lt;code&gt;pdf2csv.R&lt;/code&gt; all&amp;rsquo;interno di RStudio bisogna commentare la linea &lt;code&gt;12&lt;/code&gt; (basta aggiungere un &lt;code&gt;#&lt;/code&gt; all&amp;rsquo;inizio della riga) e attivare la riga 14 o 15 (ma solo da una delle due) togliendo il &lt;code&gt;#&lt;/code&gt; iniziale. Se si attiva la riga 14, si deve anche modificare la stringa &lt;code&gt;file-da-convertire.pdf&lt;/code&gt;, sostituendola con il nome del file da convertire. Se invece si attiva la riga numero 15, al momento dell&amp;rsquo;esecuzione dello script comparirà una finestra grafica da cui selezionare il file PDF desiderato.&lt;/p&gt;&#xA;&lt;p&gt;Nel &lt;a href=&#34;https://github.com/sabinomaggi/melabit/tree/main/un-po-di-codice&#34;&gt;repository su GitHub&lt;/a&gt; di questo articolo ho inserito dei file PDF di complessità crescente con cui fare qualche prova, fra cui un documento di quasi 1000 pagine (un vecchio manuale di riferimento del formato PDF, potevo scegliere qualcosa di diverso?), che può essere utile per valutare la velocità di conversione dello script. Non è necessario farlo a mano, il tempo di esecuzione di un qualunque programma o script si può misurare in modo preciso dal Terminale anteponendo il comando di sistema &lt;code&gt;time&lt;/code&gt;, come mostrato qui sotto.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#x9;time ./pdf2csv.R PDFReference.pdf&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Come piccola chicca finale, ho aggiunto al repository su GitHub un file PDF contenente del testo (apparentemente) nascosto, provate a convertirlo e vi accorgerete di quanto sia banale recuperare il testo completo.&lt;/p&gt;&#xA;&lt;h4 id=&#34;generare-automaticamente-dei-documenti-con-awk&#34;&gt;Generare automaticamente dei documenti con AWK&lt;/h4&gt;&#xA;&lt;p&gt;Tirar fuori il testo contenuto in un file PDF è quasi sempre solo il primo passo del lavoro, perché quello che vogliamo veramente è filtrare il contenuto del documento mantenendo solo le informazioni che ci interessano. Nel &lt;a href=&#34;https://melabit.wordpress.com/2020/11/08/il-cnr-e-anche-questo-concorsi-in-latex/&#34;&gt;caso specifico&lt;/a&gt;, io avevo bisogno di selezionare dalla domanda di concorso precedente solo i dati relativi ad una specifica tipologia di attività (ad esempio tutti gli articoli scientifici pubblicati), salvandoli in un file &lt;em&gt;ad hoc&lt;/em&gt;. E, già che c&amp;rsquo;ero, volevo anche costruire una tabella LaTeX per ciascun articolo. Una cosa abbastanza facile da fare con &lt;a href=&#34;https://www.grymoire.com/Unix/Awk.html&#34;&gt;AWK&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Di AWK ho già parlato &lt;a href=&#34;https://melabit.wordpress.com/2019/02/18/script-per-tutti-i-giorni-entra-in-scena-awk/&#34;&gt;tempo fa&lt;/a&gt; e non mi ripeterò, dirò solo che è un linguaggio ideale per analizzare un file di testo una riga alla volta, verificando se si presentano determinate condizioni ed eseguendo le operazioni programmate corrispondenti.&lt;/p&gt;&#xA;&lt;p&gt;Nonostante i suoi tanti pregi, AWK ha una limitazione piuttosto seria: per come è strutturato, AWK deve per forza di cose esaminare tutto il file senza poter &lt;em&gt;tornare indietro&lt;/em&gt;, e quindi è piuttosto difficile fargli eseguire delle operazioni basate su condizioni multiple complesse. È molto meglio (quando è possibile) scrivere più &lt;em&gt;script&lt;/em&gt; AWK, da eseguire in sequenza sullo stesso file di partenza o sull&amp;rsquo;output generato dallo script precedente, piuttosto che cercare di combattere con le limitazioni del linguaggio, complicando a dismisura il codice.&lt;/p&gt;&#xA;&lt;p&gt;In una prima versione di questo articolo avevo pensato di utilizzare un breve estratto della mia domanda di concorso precedente per descrivere il funzionamento degli script in AWK. Ma mentre scrivevo mi sono accorto che il discorso sarebbe stato così specifico da essere quasi inutile. Ho preferito quindi preparare un piccolo file PDF tratto dagli ultimi post pubblicati su Melabit, con l&amp;rsquo;intestazione in &lt;a href=&#34;https://blog.stackpath.com/yaml/&#34;&gt;YAML&lt;/a&gt;&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; di ciascun post seguita dalla prima frase del testo in &lt;a href=&#34;https://daringfireball.net/projects/markdown/&#34;&gt;Markdown&lt;/a&gt; e, quando c&amp;rsquo;è, dal link all&amp;rsquo;immagine iniziale. L&amp;rsquo;ho scelto perché la struttura di questo file assomiglia moltissimo a quella della mia domanda di concorso ma, allo stesso tempo, può essere uno schema di partenza applicabile a casi più generali.&lt;/p&gt;&#xA;&lt;div style = &#34;border-style: solid; border-width: 0px 0px 0px 4px; border-color: midnightblue; background-color: aliceblue; padding: 1em;&#34;&gt;&#xA;Questo file PDF può essere considerato come la stampa di un piccolo _database_ di informazioni correlate, dove ogni post è un _record_, suddiviso a sua volta nei vari _campi_, rappresentati dalle righe di intestazione e dalla frase di testo.&#xA;&lt;/div&gt;&#xA;&lt;p&gt;Il file PDF si chiama &lt;code&gt;Melabit ultimi post.pdf&lt;/code&gt; e, come gli altri file PDF, è disponibile nel &lt;a href=&#34;https://github.com/sabinomaggi/melabit/tree/main/un-po-di-codice&#34;&gt;repository su GitHub&lt;/a&gt; di questo articolo. Se lo aprite con Anteprima, noterete subito che ci sono delle righe vuote che separano chiaramente un post (nel linguaggio dei database, un &lt;em&gt;record&lt;/em&gt;) dall&amp;rsquo;altro. Ma convertendo il file in testo,&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#x9;./pdf2csv.R &amp;#34;Melabit ultimi post.pdf&amp;#34;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(le virgolette sono necessarie perché il nome del file contiene degli spazi), le righe vuote scompaiono e le uniche interruzioni presenti nei due file CSV prodotti dallo script di conversione corrispondono al cambio pagina. Non so se questo sia un baco o una caratteristica voluta di &lt;code&gt;pdftools&lt;/code&gt;, ma sta di fatto che è una particolarità con la quale dobbiamo fare i conti se vogliamo analizzare il testo con AWK.&lt;/p&gt;&#xA;&lt;p&gt;Sembra una sciocchezza, ma senza le giuste interruzioni non è immediato riconoscere la fine di un record &lt;em&gt;prima&lt;/em&gt; di iniziare ad esaminare quello successivo, in modo da chiudere correttamente la tabella LaTeX corrispondente al record appena esaminato e ad aprire quella relativa al record successivo. Inoltre, mentre in questo caso specifico la struttura del file PDF è volutamente molto semplice e ripetibile, nella maggior parte dei casi reali il documento da cui estrarre i dati può contenere informazioni strutturate in modi diversi, i campi da analizzare possono essere distribuiti in modo irregolare o mancare del tutto e ci possono essere incongruenze nella loro denominazione. Gestire tutti i casi possibili con un unico script lo renderebbe rapidamente troppo complesso.&lt;/p&gt;&#xA;&lt;p&gt;Molto meglio affrontare il problema un pezzetto alla volta, utilizzando uno script specifico per ciascun tipo di informazione da estrarre (io ho avuto bisogno di 6 script AWK per eseguire tutto il lavoro di esportazione dei dati, o meglio &lt;em&gt;quasi tutto&lt;/em&gt; il lavoro, perché per i casi meno frequenti ho preferito il buon vecchio copia-incolla manuale). In fondo è la stessa logica di Unix, che mette a disposizione un gran numero di strumenti semplici che messi insieme, come tanti mattoncini Lego, riescono a fare cose incredibili.&lt;/p&gt;&#xA;&lt;p&gt;Un primo script, &lt;code&gt;addblanklines.awk&lt;/code&gt;, può servire per inserire nel file CSV di partenza una riga vuota &lt;em&gt;prima&lt;/em&gt; di ogni record (una cosa piuttosto semplice da fare in questo caso, dato che ogni post inizia sempre con la stringa &amp;ldquo;layout: post&amp;rdquo;). Lo script, appena quindici linee di codice, lo trovate &amp;ldquo;in bella&amp;rdquo; nell&amp;rsquo;immagine qui sotto (ma anche in questo caso il &lt;a href=&#34;https://github.com/sabinomaggi/melabit/tree/main/un-po-di-codice&#34;&gt;sorgente&lt;/a&gt; è su GitHub).&lt;/p&gt;&#xA;&lt;img src=&#34;https://melabit.files.wordpress.com/2020/11/addblanklines-1.png&#34; alt=&#34;&#34;&gt;&lt;p&gt;Bastano solo due linee di codice, la #4 e la #9, per aggiungere le righe vuote al posto giusto. Ma già che ci siamo, è conveniente dare anche una &lt;em&gt;ripulita&lt;/em&gt; al file CSV togliendo le righe inutili, come quelle che contengono il numero di pagina o la stringa &lt;code&gt;---&lt;/code&gt; che segna l&amp;rsquo;inizio e la fine dell&amp;rsquo;intestazione in YAML (linee #5 e #12). Eseguendo lo script sul file CSV originale, si ottiene un nuovo file CSV con i vari record ben separati uno dall&amp;rsquo;altro.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#x9;./addblanklines.awk &amp;#34;Melabit ultimi post-clean.csv&amp;#34; &amp;gt; file-con-righe-vuote.csv&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Fatto questo, il passo successivo è semplice. Basta scansionare il file CSV appena generato, &lt;code&gt;file-con-righe-vuote.csv&lt;/code&gt;, in cerca della stringa &lt;em&gt;target&lt;/em&gt; &lt;code&gt;layout: post&lt;/code&gt; e, ogni volta che se ne trova una, generare una nuova tabella LaTeX riempiendola con i dati tratti dalle voci (o più propriamente &lt;em&gt;campi&lt;/em&gt;) successive. Il codice del secondo script, &lt;code&gt;cvs2table.awk&lt;/code&gt;, è visibile nell&amp;rsquo;immagine qui sotto (mentre il &lt;a href=&#34;https://github.com/sabinomaggi/melabit/tree/main/un-po-di-codice&#34;&gt;sorgente&lt;/a&gt; è sempre su GitHub).&lt;/p&gt;&#xA;&lt;img src=&#34;https://melabit.files.wordpress.com/2020/11/cvs2table-1.png&#34; alt=&#34;&#34;&gt;&lt;p&gt;Lo script è relativamente lungo, sono più di 80 linee di codice, compresi commenti e righe vuote, ma una gran parte serve per implementare la funzione (linee #3-25) che riarrangia le informazioni presenti su più linee consecutive del file CSV in modo che vengano stampate su un&amp;rsquo;unica riga, e per generare la struttura di base del documento LaTeX (linee #35-42 e #83).&lt;/p&gt;&#xA;&lt;p&gt;Tolte queste, il resto del codice è semplice, si tratta più che altro di scrivere le stringe giuste al momento giusto e di tenere conto dei casi in cui le informazioni si estendono su più linee consecutive (come succede ad esempio alle linee #61-62 e #66-73). Non entrerò nei dettagli di come funziona lo script, questo non è un corso di AWK (né tantomeno di R), basterà per ora dire che è scritto in modo da essere facilmente adattato a gestire esigenze analoghe. Per usarlo, si deve eseguire lo script usando come file di input &lt;code&gt;file-con-righe-vuote.csv&lt;/code&gt; e salvando il risultato dell&amp;rsquo;elaborazione in un file LaTeX, che qui sotto ho chiamato (con la mia solita scarsa fantasia) &lt;code&gt; lista-articoli.tex&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#x9;./cvs2table.awk file-con-righe-vuote.csv &amp;gt; lista-articoli.tex&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;mettere-tutto-insieme&#34;&gt;Mettere tutto insieme&lt;/h4&gt;&#xA;&lt;p&gt;Proviamo allora ad eseguire tutti insieme gli script presentati in questo articolo, in modo da ottenere il risultato finale desiderato. Dobbiamo prima di tutto convertire il file PDF in CSV con&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#x9;./pdf2csv.R &amp;#34;Melabit ultimi post.pdf&amp;#34;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;che genera automaticamente il file &amp;ldquo;Melabit ultimi post-clean.csv&amp;rdquo;. Fatto questo, si eseguono in sequenza i due script AWK, salvando l&amp;rsquo;output del primo in un file intermedio.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#x9;./addblanklines.awk &amp;#34;Melabit ultimi post-clean.csv&amp;#34; &amp;gt; file-con-righe-vuote.csv&#xA;&#x9;./cvs2table.awk file-con-righe-vuote.csv &amp;gt; lista-articoli.tex&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Il risultato finale è un file LaTeX ben ordinato con una tabella per ogni articolo, come quello mostrato nella figura qui sotto la cui regolarità, messa in evidenza dai colori delle parole chiave, fa pensare ad uno spartito musicale.&lt;/p&gt;&#xA;&lt;img src=&#34;https://melabit.files.wordpress.com/2020/11/lista-articoli-1.png&#34; alt=&#34;&#34;&gt;&lt;p&gt;Ma ha senso creare un file intermedio solo per trasferire l&amp;rsquo;output del primo script al secondo? Molto meglio usare il &lt;a href=&#34;https://www.geeksforgeeks.org/piping-in-unix-or-linux/&#34;&gt;meccanismo di &lt;em&gt;piping&lt;/em&gt;&lt;/a&gt; tipico in Unix, con il quale si può trasferire automaticamente il risultato dell&amp;rsquo;esecuzione di un comando all&amp;rsquo;ingresso di quello successivo, collegandoli con il carattere &lt;code&gt;|&lt;/code&gt; (&lt;em&gt;pipe&lt;/em&gt;)?&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; Con il &lt;em&gt;piping&lt;/em&gt;, i due comandi AWK precedenti possono essere eseguiti uno dopo l&amp;rsquo;altro in questo modo,&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#x9;./addblanklines.awk &amp;#34;Melabit ultimi post-clean.csv&amp;#34; | ./cvs2table.awk &amp;gt; lista-articoli.tex&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;evitando l&amp;rsquo;uso di un file intermedio. In questo caso non fa molta differenza, ma quando si devono trattare file molto grossi, il &lt;em&gt;piping&lt;/em&gt; è molto più efficiente (con i velocissimi dischi SSD odierni non ce ne accorgiamo più, ma ai tempi dei dischi meccanici la scrittura di grossi file sul disco era un vero collo di bottiglia) e, cosa che non guasta mai, evita di intasare il disco rigido con un gran numero di file inutili.&lt;/p&gt;&#xA;&lt;p&gt;E poi il &lt;em&gt;piping&lt;/em&gt; è un meccanismo intrinsecamente elegante, che non a caso è stato adottato anche in alcuni &lt;a href=&#34;http://leetschau.github.io/pipe-operator-in-functional-programming-languages.html&#34;&gt;linguaggi di programmazione odierni&lt;/a&gt;, come si può vedere nello script R mostrato nella prima parte di questo articolo (linee #24-25 e #35-37), dove il simbolo &lt;code&gt;|&lt;/code&gt; usato in Unix è sostituito dalla strana combinazione di caratteri &lt;code&gt;%&amp;amp;#62;%&lt;/code&gt;, piuttosto fastidiosa da scrivere con una tastiera italiana (io almeno sbaglio sempre qualcosa).&lt;/p&gt;&#xA;&lt;h4 id=&#34;conclusioni&#34;&gt;Conclusioni&lt;/h4&gt;&#xA;&lt;p&gt;Chi ha l&amp;rsquo;occhio allenato si accorgerà facilmente che il file LaTeX risultante contiene alcuni errori piuttosto evidenti. Li ho lasciati apposta non solo per non complicare ulteriormente il codice, ma anche per mostrare quanto sia complicato il lavoro di estrazione automatica dei dati da file strutturati in modo non perfettamente regolare. Non è certo un caso che in questo campo ci sia una grossa attività di ricerca che prova a superare gli ostacoli e a rendere il tutto il più semplice e il più efficiente possibile.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;Il comando &lt;code&gt;time&lt;/code&gt; è presente di default nei sistemi operativi Unix come Linux e macOS. Su Windows &lt;code&gt;time&lt;/code&gt; non esiste, ma si possono usare degli &lt;a href=&#34;https://qastack.it/superuser/228056/windows-equivalent-to-unix-time-command&#34;&gt;strumenti equivalenti&lt;/a&gt;.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;YAML è un linguaggio di &lt;em&gt;markup&lt;/em&gt; particolarmente adatto per definire dei file di configurazione e, in generale, per rappresentare informazioni strutturate in modo semplice e leggibile, molto più facile da usare di strumenti più noti come XML e JSON.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:3&#34;&gt;&#xA;&lt;p&gt;Il &lt;em&gt;piping&lt;/em&gt; è uno dei meccanismi principali che rendono Unix una specie di Lego informatico.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
    </item>
    <item>
      <title>Script per tutti i giorni: entra in scena awk</title>
      <link>https://melabit.com/it/2019/02/18/script-per-tutti-i-giorni-entra-in-scena-awk/</link>
      <pubDate>Mon, 18 Feb 2019 18:00:00 +0000</pubDate>
      <guid>https://melabit.com/it/2019/02/18/script-per-tutti-i-giorni-entra-in-scena-awk/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://www.viscountinstruments.it/wp-content/uploads/2020/01/ebano_3-600x433.jpg&#34; alt=&#34;&#34;&gt;&#xA;&amp;ndash; &lt;em&gt;&lt;a href=&#34;https://www.viscountinstruments.it/instrument/a-w-k-keyboard/&#34;&gt;Tastiera A.W.K., Viscount Instruments&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Nelle prime tre puntate di questa serie abbiamo imparato a scrivere uno script in &lt;code&gt;bash&lt;/code&gt; per trasformare una stringa di testo in modo che segua delle  convenzioni ben determinate a priori (qui i link alla &lt;a href=&#34;https://melabit.wordpress.com/2018/11/23/script-per-tutti-i-giorni-semplici-modifiche-alle-stringhe-di-testo/&#34;&gt;prima&lt;/a&gt;, &lt;a href=&#34;https://melabit.wordpress.com/2018/12/05/script-per-tutti-i-giorni-dalla-linea-di-comando-al-programma/&#34;&gt;seconda&lt;/a&gt; e &lt;a href=&#34;https://melabit.wordpress.com/2018/12/30/script-per-tutti-i-giorni-shell-e-parametri/&#34;&gt;terza&lt;/a&gt; puntata).&lt;/p&gt;&#xA;&lt;p&gt;In questo caso particolare, la stringa risultante dalla trasformazione deve essere scritta tutta in minuscolo e non deve contenere apostrofi o altri caratteri speciali, a parte il trattino usato come separatore di parole. L&amp;rsquo;idea è quella di usare questa stringa, insieme alla data di pubblicazione del post, per dare un nome standard e facilmente rintracciabile al file Markdown che contiene il testo del post stesso, &lt;a href=&#34;https://melabit.wordpress.com/2018/11/23/script-per-tutti-i-giorni-semplici-modifiche-alle-stringhe-di-testo/&#34;&gt;utilizzando il formato&lt;/a&gt; &lt;code&gt;YYYY-MM-DD-titolo-del-post.md&lt;/code&gt;, dove &lt;code&gt;YYYY&lt;/code&gt; indica l’anno, &lt;code&gt;MM&lt;/code&gt; il mese e &lt;code&gt;DD&lt;/code&gt; il giorno di pubblicazione.&lt;/p&gt;&#xA;&lt;p&gt;L&amp;rsquo;approccio &lt;a href=&#34;https://melabit.wordpress.com/2018/12/30/script-per-tutti-i-giorni-shell-e-parametri/&#34;&gt;seguito finora&lt;/a&gt; è utile per imparare i fondamenti della programmazione in &lt;code&gt;bash&lt;/code&gt;, ma manca decisamente di praticità. Partire dal titolo e dalla data di pubblicazione presenti nell&amp;rsquo;intestazione del post per arrivare al nome completo del file richiede un certo lavoro di copia e incolla fra l&amp;rsquo;editor, il Finder e il Terminale, e gli errori sono sempre in agguato.&lt;/p&gt;&#xA;&lt;p&gt;Quello che ci vuole è uno script che renda il processo completamente automatico, rinominando il file Markdown a partire dal contenuto del documento stesso.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#xA;&lt;p&gt;Si potrebbe benissimo fare anche con &lt;code&gt;bash&lt;/code&gt;, ma perché complicarsi la vita quando c&amp;rsquo;è uno strumento fatto apposta per analizzare ed estrarre dei dati dai file di testo?&lt;/p&gt;&#xA;&lt;h4 id=&#34;awk-questo-sconosciuto&#34;&gt;AWK, questo sconosciuto&lt;/h4&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/onetrueawk/awk&#34;&gt;AWK&lt;/a&gt; è un linguaggio di programmazione interpretato sviluppato negli anni &amp;lsquo;70 presso i &lt;a href=&#34;https://it.wikipedia.org/wiki/Bell_Laboratories&#34;&gt;Bell Labs&lt;/a&gt;, il famosissimo centro di ricerca americano che ci ha dato il transistor, il laser, Unix e il C (e moltissimo altro). AWK è stato sviluppato da Alfred Aho, Peter Weinberger e Brian Kernighan, tre grandi studiosi di &lt;em&gt;computer science&lt;/em&gt;, fra i quali spicca il terzo, coautore insieme a Dennis Ritchie di &lt;a href=&#34;https://archive.org/stream/CProgLangBooksCollection/1_TheCProgLang-2ndEd-RitchieKernighan#page/n17/mode/2up&#34;&gt;The C Programming Language&lt;/a&gt;, il volume di riferimento sul linguaggio C, noto anche semplicemente come &amp;ldquo;K&amp;amp;R&amp;rdquo; dai cognomi dei due autori.&lt;/p&gt;&#xA;&lt;p&gt;Alla base di AWK c&amp;rsquo;è l&amp;rsquo;idea di elaborare un file di testo una riga alla volta, controllando che la riga in esame soddisfi una o più condizioni prestabilite ed eseguendo le azioni programmate per ciascuna di queste condizioni&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;    condizione #1: {azione #1}&#xA;    condizione #2: {azione #2}&#xA;    ...&#xA;    condizione #N: {azione #N}   &#xA;    &#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Per AWK un file di testo è costituito da un certo numero di righe (&lt;em&gt;record&lt;/em&gt;), ciascuna delle quali è suddivisa in uno o più campi (&lt;em&gt;field&lt;/em&gt;), separati fra loro da un &lt;em&gt;separatore di campo&lt;/em&gt;, che di default è lo spazio ma che può essere modificato a piacere. Per riferirsi a ciascun campo AWK usa le variabili speciali &lt;code&gt;$1&lt;/code&gt;, &lt;code&gt;$2&lt;/code&gt; e così via, dove il numero indica la posizione del campo all&amp;rsquo;interno della riga. La variabile &lt;code&gt;$0&lt;/code&gt; contiene l&amp;rsquo;intera riga corrente.&lt;/p&gt;&#xA;&lt;p&gt;Tutto qui? Più o meno. C&amp;rsquo;è (quasi) solo da aggiungere che AWK prevede due azioni speciali opzionali, racchiuse fra i blocchi &lt;code&gt;BEGIN {...}&lt;/code&gt;, &lt;code&gt;END {...}&lt;/code&gt;, che servono per eseguire le operazioni preliminari e conclusive necessarie per il buon funzionamento del programma, ad esempio per definire il separatore di campo. Un programma completo in AWK ha quindi una struttura di questo tipo,&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;    BEGIN { istruzione&#xA;            istruzione&#xA;            ....&#xA;          }&#xA;    &#xA;    condizione #1: { istruzione&#xA;                     istruzione&#xA;                     ....&#xA;                   }&#xA;    condizione #2: { istruzione&#xA;                     istruzione&#xA;                     ....&#xA;                   }&#xA;&#xA;    ...&#xA;    condizione #N: { istruzione&#xA;                     istruzione&#xA;                     istruzione&#xA;                     ....&#xA;                   }&#xA;&#xA;     END { istruzione&#xA;           istruzione&#xA;           ....&#xA;         }&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;dove come già detto i blocchi &lt;code&gt;BEGIN {...}&lt;/code&gt;, &lt;code&gt;END {...}&lt;/code&gt; sono opzionali.&lt;/p&gt;&#xA;&lt;p&gt;Nonostante la fama dei suoi autori, AWK è poco utilizzato, molto meno di quanto meriterebbe, i programmatori del mondo UNIX preferiscono usare strumenti più semplici ma meno potenti come &lt;code&gt;sed&lt;/code&gt; (che abbiamo già incontrato nelle &lt;a href=&#34;https://melabit.wordpress.com/2018/11/23/script-per-tutti-i-giorni-semplici-modifiche-alle-stringhe-di-testo/&#34;&gt;puntate&lt;/a&gt; &lt;a href=&#34;https://melabit.wordpress.com/2018/12/05/script-per-tutti-i-giorni-dalla-linea-di-comando-al-programma/&#34;&gt;precedenti&lt;/a&gt;) o il declinante &lt;code&gt;perl&lt;/code&gt;, un linguaggio di manipolazione di file di testo perfetto per i programmatori che mitizzano Tafazzi.&lt;/p&gt;&#xA;&lt;p&gt;AWK invece ha il giusto equilibrio di potenza e semplicità d&amp;rsquo;uso ed è uno strumento perfetto se gli si chiede di fare quello per cui è stato ideato, elaborare informazioni strutturate contenute in file di testo.&lt;/p&gt;&#xA;&lt;p&gt;Per fortuna AWK è installato di default in macOS e in Linux, oltre che in tutti i sistemi operativi basati su UNIX che si trovano in giro, per cui per provarlo basta lanciare il Terminale ed eseguire il comando &lt;code&gt;awk&lt;/code&gt;. In realtà ci sono in giro almeno due versioni diverse di AWK. In macOS è installato &lt;code&gt;awk&lt;/code&gt; &lt;em&gt;liscio&lt;/em&gt;, la versione del linguaggio definita dai tre autori originali nel volume &lt;a href=&#34;https://archive.org/details/pdfy-MgN0H1joIoDVoIC7&#34;&gt;The AWK programming language&lt;/a&gt;. Su Linux, invece, si trova in genere &lt;code&gt;gawk&lt;/code&gt;, una &lt;a href=&#34;https://www.gnu.org/software/gawk/manual/&#34;&gt;implementazione&lt;/a&gt; del linguaggio della Free Software Foundation pienamente compatibile con &lt;code&gt;awk&lt;/code&gt;, a cui sono state aggiunte alcune estensioni piuttosto utili. Installare &lt;code&gt;gawk&lt;/code&gt; su macOS è facile per chi usa &lt;a href=&#34;https://melabit.wordpress.com/2014/04/29/homebrew-software-per-il-mac-fatto-in-casa/&#34;&gt;Homebrew&lt;/a&gt;, dal Terminale&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;$ brew install gawk&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Da ora in poi per semplicità farò cadere la distinzione fatta finora fra AWK, il linguaggio di programmazione, e &lt;code&gt;awk&lt;/code&gt;, l&amp;rsquo;interprete del linguaggio, usando sempre e solo il termine awk per riferirmi ad entrambi.&lt;/p&gt;&#xA;&lt;h4 id=&#34;un-programma-banale-in-awk&#34;&gt;Un programma banale in awk&lt;/h4&gt;&#xA;&lt;p&gt;Per avere una idea di cosa può fare awk, ecco un piccolissimo (e rozzo) programma di esempio,&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;BEGIN { FS = &amp;#34;,&amp;#34;&#xA;        OFS = &amp;#34;, &amp;#34;&#xA;      }&#xA;&#xA;$1 ~ /Violanda/ { $1 = &amp;#34;Jolanda&amp;#34; }&#xA;                { print $2, $1, $3, $6, $4, $5 }&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;che applicato ad un elenco di indirizzi come questo,&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;NOME,COGNOME,INDIRIZZO,LOCALITA,PROVINCIA,CAP&#xA;Massino,Nardini,Via Roma 8,Grana,AT,14031&#xA;Primo,Sabbatini,Via C. Cattaneo 50,Cala di Volpe,SS,07020&#xA;Giuseppe,Marino,Via C. Alberto 75,Barni,CO,22030&#xA;Ivano,Costa,Via Guantai Nuovi 29,Ischia,NA,80077&#xA;Margherita,Davide,Via Nuova Agnano 83,Rufina,FI,50068&#xA;Daphne,Lettiere,Via R. Conforti 67,Castel Di Ieri,AQ,67020&#xA;Violanda,Lori,Via A. Manzoni 101,Parona,PV,27020&#xA;Luigia,Cremonesi,Via Castelfidardo 145,Cittadella Del Capo,CS,87020&#xA;Fiore,Mucciano,Via Valpantena 120,Buccino Stazione,SA,84020&#xA;Sandra,Greco,Via Pisanelli 140,Castiglione D&amp;#39;Adda,LO,26823&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;scambia la posizione del nome e del cognome e sposta il CAP prima della Località in tutte le righe del file. Già che c&amp;rsquo;è, corregge anche il nome sbagliato &amp;ldquo;Violanda&amp;rdquo; e lo trasforma in &amp;ldquo;Jolanda&amp;rdquo;. Nella riga #5, &lt;code&gt;$1 ~ /Violanda/&lt;/code&gt; è la condizione, e &lt;code&gt;{$1 = &amp;quot;Jolanda&amp;quot;}&lt;/code&gt; l&amp;rsquo;azione relativa, mentre nella riga #6 la condizione è vuota e quindi l&amp;rsquo;azione conseguente &lt;code&gt;{print $2, $1, $3, $6, $4, $5}&lt;/code&gt; si applica a tutte le righe del file. Il blocco &lt;code&gt;BEGIN {...}&lt;/code&gt; serve per definire il carattere (o i caratteri) che separa i campi contenuti in ciascuna riga letta o scritta dal programma: la variabile predefinita &lt;code&gt;FS&lt;/code&gt; è il separatore dei campi del file di input (quello letto dal programma), &lt;code&gt;OFS&lt;/code&gt; è il separatore dei campi delle righe stampate dallo script.&lt;/p&gt;&#xA;&lt;p&gt;Per provarlo, copiate il programma in un editor e salvatelo come &lt;code&gt;swap.awk&lt;/code&gt;, poi copiate la lista di indirizzi e salvatela come &lt;code&gt;address.csv&lt;/code&gt; (meglio se salvate i due file nella cartella &lt;code&gt;~/Development&lt;/code&gt;, &lt;a href=&#34;https://melabit.wordpress.com/2018/12/30/script-per-tutti-i-giorni-shell-e-parametri/&#34;&gt;ricordate&lt;/a&gt;?). Infine lanciate il Terminale, eseguite il comando&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;$ awk -f swap.awk address.csv &#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;e vedete cosa viene fuori. Provate a cambiare &lt;code&gt;OFS&lt;/code&gt; e a vedere che succede.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;Domanda 1: Come si fa a lanciare lo script senza dover premettere il comando &lt;code&gt;awk&lt;/code&gt;?&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;Domanda 2: Se si rimuove la variabile &lt;code&gt;FS&lt;/code&gt; dal blocco &lt;code&gt;BEGIN{...}&lt;/code&gt; lo script continua a funzionare correttamente?&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;Ma basta con awk. Questo articolo non vuole essere una introduzione al linguaggio ma vuole solo mostrare come si può risolvere con AWK il problema che ci sta a cuore. Chi volesse è approfondire la conoscenza del linguaggio può consultare i volumi e le guide online riportate in bibliografia.&lt;/p&gt;&#xA;&lt;h4 id=&#34;rinominare-automaticamente-un-post&#34;&gt;Rinominare automaticamente un post&lt;/h4&gt;&#xA;&lt;p&gt;E finalmente eccoci al programma &lt;code&gt;awk&lt;/code&gt; che rinomina da solo il file Markdown di un post in base al titolo e alla data contenuti nei &lt;a href=&#34;https://melabit.wordpress.com/2018/11/23/script-per-tutti-i-giorni-semplici-modifiche-alle-stringhe-di-testo/&#34;&gt;metadati del documento&lt;/a&gt;, che contengono, fra l&amp;rsquo;altro, il titolo, la data di pubblicazione, la categoria e i tag associati al post stesso.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;BEGIN { FS = &amp;#34; &amp;#34;&#xA;        OFS = &amp;#34;-&amp;#34;&#xA;        EXT = &amp;#34;.md&amp;#34;&#xA;      }&#xA;&#xA;$1 ~ /[Dd]ate:/   { date = $2 }&#xA;$1 ~ /[Tt]itle:/  { title = &amp;#34;&amp;#34;&#xA;                    for (i = 2; i &amp;lt;= NF; i++) {&#xA;                        title = title FS tolower($i)&#xA;                    }&#xA;                  }&#xA;&#xA;END { newfilename = date OFS title&#xA;      gsub(&amp;#34;[[:cntrl:]]&amp;#34;, &amp;#34;&amp;#34;, newfilename)&#xA;      gsub(&amp;#34;[\&amp;#34;]+&amp;#34;, &amp;#34;&amp;#34;, newfilename)&#xA;      gsub(&amp;#34;[\.,;:!\?&amp;amp;\$]+&amp;#34;, &amp;#34;&amp;#34;, newfilename)&#xA;      gsub(&amp;#34;[-| ]+&amp;#34;, &amp;#34;-&amp;#34;, newfilename)&#xA;      newfilename = newfilename EXT&#xA;      system(&amp;#34;mv &amp;#34; FILENAME &amp;#34; &amp;#34; newfilename)&#xA;    }&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Riassumo brevemente cosa fa il programma, chi non fosse interessato può saltare direttamente al prossimo paragrafo. La prima condizione &lt;code&gt;$1 ~ /[Dd]ate/&lt;/code&gt; cerca la stringa &lt;code&gt;date:&lt;/code&gt; (indifferentemente in minuscolo o maiuscolo) nel primo campo di tutte le righe del post e quando la trova assegna il secondo campo, corrispondente alla data, alla variabile &lt;code&gt;date&lt;/code&gt;.&#xA;La seconda condizione fa lo stesso per il titolo e lo assegna alla variabile &lt;code&gt;title&lt;/code&gt;. Poiché il titolo è distribuito su un numero imprecisato di campi (ricordo che il separatore di campo &lt;code&gt;FS&lt;/code&gt; è lo spazio), viene utilizzato un ciclo &lt;code&gt;for&lt;/code&gt; per leggere ed aggiungere in successione a &lt;code&gt;title&lt;/code&gt; tutti i campi della riga successivi al primo. Il numero di campi presenti nella riga del titolo è contenuto nella variabile di sistema &lt;code&gt;NF&lt;/code&gt;, aggiornata automaticamente dall&amp;rsquo;interprete ogni volta che viene letta una nuova riga.&#xA;La parte finale del programma, racchiusa nel blocco &lt;code&gt;END {...}&lt;/code&gt;, si occupa di definire la variabile &lt;code&gt;newfilename&lt;/code&gt;, contenente il nuovo nome da assegnare al file, e di trasformarla secondo le regole desiderate.&#xA;La variabile &lt;code&gt;newfilename&lt;/code&gt; contiene inizialmente (riga #12) la data e il titolo letti nel post, separati da un trattino (il valore di &lt;code&gt;OFS&lt;/code&gt;). Nelle quattro righe successive viene utilizzata la funzione &lt;code&gt;gsub&lt;/code&gt; per rimuovere da questa variabile tutti i caratteri indesiderati (caratteri di controllo, virgolette, punteggiatura) e per sostituire spazi e trattini (anche multipli) con un trattino singolo. Alla riga #17 viene aggiunta l&amp;rsquo;estensione definita in &lt;code&gt;EXT&lt;/code&gt;, mentre l&amp;rsquo;ultima riga del blocco effettua una chiamata al sistema operativo per rinominare effettivamente il file, utilizzando un&amp;rsquo;altra variabile di sistema, &lt;code&gt;FILENAME&lt;/code&gt;, che contiene il nome originale del file Markdown su cui sta operando lo script.&lt;/p&gt;&#xA;&lt;p&gt;Salviamo il programma nella solita cartella &lt;code&gt;Development&lt;/code&gt; con il nome &lt;code&gt;setpostname.awk&lt;/code&gt;. Per provarlo dobbiamo avere anche un file Markdown contenente nell&amp;rsquo;intestazione (&lt;em&gt;header&lt;/em&gt;) almeno i metadati relativi al titolo e alla data. Possiamo prendere la prima parte di questo post,&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;---&#xA;layout: post  &#xA;title: &amp;#34;Script per tutti i giorni: entra in scena awk&amp;#34;  &#xA;author:&#x9;Sabino Maggi  &#xA;date: 2019-02-18T18:00:00  &#xA;categories:  &#xA;  - programmazione  &#xA;tags:  &#xA;  - awk  &#xA;  - bash  &#xA;  - editor  &#xA;  - gawk  &#xA;  - perl  &#xA;  - script  &#xA;  - terminale  &#xA;comments: true  &#xA;sidebar: true  &#xA;toc: true  &#xA;published: 2019-02-18T18:00:00  &#xA;slug:  &#xA;&#xA;---&#xA;&#xA;Nelle prime tre puntate di questa serie abbiamo imparato a scrivere uno script in `bash` per trasformare una stringa di testo in modo che segua delle  convenzioni ben determinate a priori (qui i link alla [prima](https://melabit.wordpress.com/2018/11/23/script-per-tutti-i-giorni-semplici-modifiche-alle-stringhe-di-testo/), [seconda](https://melabit.wordpress.com/2018/12/05/script-per-tutti-i-giorni-dalla-linea-di-comando-al-programma/) e [terza](https://melabit.wordpress.com/2018/12/30/script-per-tutti-i-giorni-shell-e-parametri/) puntata).&#xA;&#xA;In questo caso particolare,...&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;e salvarlo con un nome qualsiasi nella stessa cartella &lt;code&gt;Development&lt;/code&gt;. Poiché la fantasia fa difetto, chiamiamolo &lt;code&gt;articolo.md&lt;/code&gt;. A questo punto lanciamo il Terminale, spostiamoci nella cartella &lt;code&gt;Development&lt;/code&gt;&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;$ cd ~/Development&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;e lanciamo lo script in &lt;code&gt;awk&lt;/code&gt; con il comando&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;$  /usr/bin/awk -f setpostname.awk articolo.md&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;e voilà, il file &lt;code&gt;articolo.md&lt;/code&gt; viene rinominato automaticamente in &lt;code&gt;2019-02-18-script-per-tutti-i-giorni-entra-in-scena-awk&lt;/code&gt;, che è esattamente quello che volevamo. Nota per i più curiosi:  dato che &lt;code&gt;awk&lt;/code&gt; ha bisogno di sapere sia il nome dello script contenente i comandi che quello del file da elaborare, si usa l&amp;rsquo;opzione &lt;code&gt;-f&lt;/code&gt; per indicare esplicitamente lo script con i comandi.&lt;/p&gt;&#xA;&lt;p&gt;Perché uso l&amp;rsquo;intero percorso &lt;code&gt;/usr/bin/awk&lt;/code&gt; per richiamare &lt;code&gt;awk&lt;/code&gt;? Semplicemente perché voglio essere sicuro di utilizzare l&amp;rsquo;interprete &lt;code&gt;awk&lt;/code&gt; presente di default in macOS e non la versione estesa installata tramite Homebrew, che funziona in modo leggermente diverso e darebbe degli avvertimenti poco incomprensibili, pur riuscendo lo stesso a rinominare correttamente il file.&lt;/p&gt;&#xA;&lt;h4 id=&#34;conclusioni&#34;&gt;Conclusioni&lt;/h4&gt;&#xA;&lt;p&gt;Ormai siamo quasi a posto con la rinominazione automatica di un post in Markdown (che poi in effetti è solo una scusa per gettare le basi e per poter affrontare script complessi e più utili). Manca solo un piccolissimo dettaglio, che può far diventare questo script del tutto indistinguibile dai comandi standard del sistema operativo e che sarà l&amp;rsquo;argomento della prossima puntata.&lt;/p&gt;&#xA;&lt;h4 id=&#34;bibliografia&#34;&gt;Bibliografia&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Alfred Aho, Brian Kernighan, Peter Weinberger, &lt;a href=&#34;https://archive.org/details/pdfy-MgN0H1joIoDVoIC7&#34;&gt;The AWK programming language&lt;/a&gt;, Addison-Wesley, 1988.&lt;/li&gt;&#xA;&lt;li&gt;Arnold Robbins, &lt;a href=&#34;https://www.gnu.org/software/gawk/manual/&#34;&gt;Gawk: Effective AWK Programming&lt;/a&gt;, Edition 4.2, 2018.&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://matt.might.net/articles/sculpting-text/&#34;&gt;Sculpting text with regex, grep, sed, awk, emacs and vim&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Wikibooks, &lt;a href=&#34;https://en.wikibooks.org/wiki/An_Awk_Primer&#34;&gt;An Awk Primer&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Bruce Barnett, &lt;a href=&#34;http://www.grymoire.com/Unix/Awk.html&#34;&gt;Awk a Tutorial and Introduction&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Tutorials Point, &lt;a href=&#34;https://www.tutorialspoint.com/awk/index.htm&#34;&gt;Awk Tutorial&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;Una cosa che io trovo bellissima anche dal punto di vista diciamo così, &lt;em&gt;filosofico&lt;/em&gt;, e che mi ricorda i bellissimi articoli di Douglas Hofstadter su Le Scienze sui &lt;a href=&#34;http://www.repubblica.it/2003/g/rubriche/lessicoenuvole/9settemb/9settemb.html&#34;&gt;testi autoreferenziali&lt;/a&gt;.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
    </item>
    <item>
      <title>Programmare l&#39;inutilità</title>
      <link>https://melabit.com/it/2015/11/23/programmare-linutilita/</link>
      <pubDate>Mon, 23 Nov 2015 06:00:00 +0000</pubDate>
      <guid>https://melabit.com/it/2015/11/23/programmare-linutilita/</guid>
      <description>&lt;p&gt;Come tanti ricevo ogni giorno una o più email che mi propongono di visitare questo o quel sito. Non è sempre tempo perso, spesso si trovano delle vere e proprie gemme.&lt;/p&gt;&#xA;&lt;p&gt;Altre volte però scopro siti o applicazioni la cui utilità è perlomeno dubbia.&lt;/p&gt;&#xA;&lt;h4 id=&#34;img2css&#34;&gt;img2css&lt;/h4&gt;&#xA;&lt;p&gt;La palma del programma più inutile degli ultimi mesi vorrei assegnarla a &lt;a href=&#34;http://javier.xyz/img2css/&#34;&gt;img2css&lt;/a&gt;, una applicazione web scritta in JavaScript che converte una immagine bitmap (in formato png, jpg o simili) in un file CSS, che può qundi essere inserito direttamente in una pagina web.&lt;/p&gt;&#xA;&lt;p&gt;In teoria l&amp;rsquo;idea è ottima, perché permette di integrare un&amp;rsquo;immagine in una pagina web senza bisogno di collegamenti a file esterni, ma nella pratica fallisce miseramente.&lt;/p&gt;&#xA;&lt;p&gt;Anche con immagini semplicissime il file CSS generato diventa di dimensioni abnormi, ed è molto più pesante da gestire e da trasmettere in rete rispetto all&amp;rsquo;immagine originale.&lt;/p&gt;&#xA;&lt;h4 id=&#34;proviamo-img2css&#34;&gt;Proviamo img2css&lt;/h4&gt;&#xA;&lt;p&gt;Proviamo ad usare img2css con una immagine semplicissima composta da un quadrato di 10x10 pixel con bordo nero e interno bianco. L&amp;rsquo;immagine si può creare da Terminale tramite &lt;code&gt;convert&lt;/code&gt;, uno dei comandi più potenti di &lt;a href=&#34;http://www.imagemagick.org/script/index.php&#34;&gt;ImageMagick&lt;/a&gt;, in grado non solo (come dice il nome) di convertire le immagini da un formato grafico all&amp;rsquo;altro, ma anche di generare  delle immagini &lt;em&gt;ex-novo&lt;/em&gt; in praticamente qualunque formato conosciuto.&lt;/p&gt;&#xA;&lt;p&gt;Il comando&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;$ convert -size 10x10 xc:white -fill white &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;&#x9;-stroke black -draw &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rectangle 0,0 9,9&amp;#34;&lt;/span&gt; square_10x10.png&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;produce l&amp;rsquo;immagine &lt;img src=&#34;https://melabit.files.wordpress.com/2015/11/square_10x10.png&#34; alt=&#34;square_10x10&#34; width=&#34;20&#34; height=&#34;20&#34; class=&#34;wp-image-2226&#34; /&gt;, che occupa esattamente 127 byte (per maggiore chiarezza l&amp;rsquo;immagine è visualizzata al doppio della dimensione originale).&lt;/p&gt;&#xA;&lt;p&gt;Convertendo l&amp;rsquo;immagine con &lt;code&gt;img2css&lt;/code&gt;, il codice CSS corrispondente&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;style&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;height:1px;width:1px;box-shadow:#000 0 0, #000 1px 0, #000 2px 0, #000 3px 0, #000 4px 0, #000 5px 0, #000 6px 0, #000 7px 0, #000 8px 0, #000 9px 0, #000 0 1px, #000 1px 1px, #000 2px 1px, #000 3px 1px, #000 4px 1px, #000 5px 1px, #000 6px 1px, #000 7px 1px, #000 8px 1px, #000 9px 1px, #000 0 2px, #000 1px 2px, #fff 2px 2px, #fff 3px 2px, #fff 4px 2px, #fff 5px 2px, #fff 6px 2px, #fff 7px 2px, #000 8px 2px, #000 9px 2px, #000 0 3px, #000 1px 3px, #fff 2px 3px, #fff 3px 3px, #fff 4px 3px, #fff 5px 3px, #fff 6px 3px, #fff 7px 3px, #000 8px 3px, #000 9px 3px, #000 0 4px, #000 1px 4px, #fff 2px 4px, #fff 3px 4px, #fff 4px 4px, #fff 5px 4px, #fff 6px 4px, #fff 7px 4px, #000 8px 4px, #000 9px 4px, #000 0 5px, #000 1px 5px, #fff 2px 5px, #fff 3px 5px, #fff 4px 5px, #fff 5px 5px, #fff 6px 5px, #fff 7px 5px, #000 8px 5px, #000 9px 5px, #000 0 6px, #000 1px 6px, #fff 2px 6px, #fff 3px 6px, #fff 4px 6px, #fff 5px 6px, #fff 6px 6px, #fff 7px 6px, #000 8px 6px, #000 9px 6px, #000 0 7px, #000 1px 7px, #fff 2px 7px, #fff 3px 7px, #fff 4px 7px, #fff 5px 7px, #fff 6px 7px, #fff 7px 7px, #000 8px 7px, #000 9px 7px, #000 0 8px, #000 1px 8px, #000 2px 8px, #000 3px 8px, #000 4px 8px, #000 5px 8px, #000 6px 8px, #000 7px 8px, #000 8px 8px, #000 9px 8px, #000 0 9px, #000 1px 9px, #000 2px 9px, #000 3px 9px, #000 4px 9px, #000 5px 9px, #000 6px 9px, #000 7px 9px, #000 8px 9px, #000 9px 9px;&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;&amp;gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;occupa 1259 byte, circa 10 volte in più del file &lt;code&gt;png&lt;/code&gt; di partenza. Le cose peggiorano rapidamente se si usano immagini più complesse. Questa immagine da 20x20 pixel &lt;img src=&#34;https://melabit.files.wordpress.com/2015/11/concentric_color.png&#34; alt=&#34;concentric_color&#34; width=&#34;20&#34; height=&#34;20&#34; class=&#34;wp-image-2232&#34; /&gt;, composta da alcuni rettangoli concentrici colorati e generata tramite&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ convert -size 20x20 xc:white -fill white &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;-stroke black  -draw &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rectangle 0,0 19,19&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;-stroke red    -draw &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rectangle 2,2 17,17&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;-stroke green  -draw &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rectangle 4,4 15,15&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;-stroke blue   -draw &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rectangle 6,6 13,13&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;-stroke yellow -draw &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rectangle 8,8 11,11&amp;#34;&lt;/span&gt; concentric_color.png&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;occupa solo 481 byte in formato &lt;code&gt;png&lt;/code&gt;, che diventano ben 6.491 byte quando di converte l&amp;rsquo;immagine in CSS con &lt;code&gt;img2css&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Con immagini &lt;em&gt;reali&lt;/em&gt; a colori, o peggio ancora fotografie (&lt;a href=&#34;https://melabit.files.wordpress.com/2015/11/ipadpro.jpg&#34;&gt;ad esempio questa&lt;/a&gt;), le immagini CSS possono diventare anche 150-200 volte più grandi di quella originale, mettendo in ginocchio il browser (e il computer!) durante il processo di conversione o quando si copia il file CSS ottenuto in una pagina web.&lt;/p&gt;&#xA;&lt;p&gt;Provare per credere, ma se poi il Mac si pianta non prendetevela con me.&lt;/p&gt;&#xA;&lt;h4 id=&#34;dentro-il-codice&#34;&gt;Dentro il codice&lt;/h4&gt;&#xA;&lt;p&gt;Il programma &lt;a href=&#34;http://javier.xyz/img2css/&#34;&gt;img2css&lt;/a&gt; è molto semplice ed è composto poche centinaia di linee di codice JavaScript. Ma è perfino troppo lungo per quello che fa.&lt;/p&gt;&#xA;&lt;p&gt;In fondo si tratta solo di determinare il &lt;a href=&#34;http://www.rapidtables.com/web/color/RGB_Color.htm&#34;&gt;codice RGB&lt;/a&gt; di ogni pixel dell&amp;rsquo;immagine, convertirlo in &lt;a href=&#34;http://it.wikihow.com/Convertire-un-Numero-Decimale-in-Esadecimale&#34;&gt;formato esadecimale&lt;/a&gt; ed associarlo alle coordinate orizzonantali e verticali del pixel considerato.&lt;/p&gt;&#xA;&lt;p&gt;Ogni pixel viene quindi convertito nella sequenza &lt;code&gt;#AAA Xpx Ypx&lt;/code&gt;, dove &lt;code&gt;#AAA&lt;/code&gt; indica il colore in esadecimale (la stringa può essere composta da 3 o 6 numeri a seconda del colore RGB determinato) e &lt;code&gt;Xpx Ypx&lt;/code&gt; indicano le coordinate orizzonantali e verticali del pixel.&lt;/p&gt;&#xA;&lt;p&gt;Tutto questo si può fare tranquillamente da Terminale, con poche righe di codice ben piazzate.&lt;/p&gt;&#xA;&lt;h4 id=&#34;img2css-da-terminale&#34;&gt;img2css da Terminale&lt;/h4&gt;&#xA;&lt;p&gt;Per convertire un file grafico in una sequenza di colori RGB si può usare ancora &lt;code&gt;convert&lt;/code&gt; di &lt;a href=&#34;http://www.imagemagick.org/script/index.php&#34;&gt;ImageMagick&lt;/a&gt;,&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;$ convert square_10x10.png -compress none square_10x10.ppm&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;ottenendo un file in &lt;a href=&#34;http://netpbm.sourceforge.net/doc/ppm.html&#34;&gt;formato ppm&lt;/a&gt;, in cui ciascun pixel dell&amp;rsquo;immagine è rappresentato da tre numeri interi decimali, corrispondenti ai tre colori RGB del pixel stesso (il formato grafico &lt;code&gt;ppm&lt;/code&gt; è molto inefficiente, ma è utilissimo dal punto di vista didattico perché mostra chiaramente come è &lt;em&gt;fatto&lt;/em&gt; un file grafico).&lt;/p&gt;&#xA;&lt;p&gt;Le sequenze di tre  numeri decimali sono disposte per righe orizzontali a partire dalla quarta riga del file. Le prime tre righe contengono rispettivamente il &lt;em&gt;numero magico&lt;/em&gt; che definisce il tipo di file, le dimensioni dell&amp;rsquo;immagine in pixel e il valore massimo del colore RGB del file.&lt;/p&gt;&#xA;&lt;p&gt;La rappresentazione in formato &lt;code&gt;ppm&lt;/code&gt; del quadrato di 10x10 pixel con bordo nero e interno bianco &lt;img src=&#34;./file/img2css/square_10x10.png&#34; alt=&#34;&#34;&gt; mostrato sopra è&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;P3&#xA;10 10&#xA;255&#xA;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 &#xA;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 &#xA;0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 &#xA;0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 &#xA;0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 &#xA;0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 &#xA;0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 &#xA;0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 &#xA;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 &#xA;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 &#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Sequenze di dati come questa possono essere facilmente analizzate e trasformate tramite &lt;a href=&#34;http://www.grymoire.com/Unix/Awk.html&#34;&gt;awk&lt;/a&gt;, uno dei tanti potenti strumenti specifici disponibili nei sistemi operativi basati su Unix.&lt;/p&gt;&#xA;&lt;p&gt;Basta uno script &lt;code&gt;awk&lt;/code&gt; di poche righe per convertire le informazioni RGB decimali contenute nel file &lt;code&gt;ppm&lt;/code&gt; in formato esadecimale&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#!/usr/bin/awk -f&#xA;&#xA;/^255/  { while (getline == 1)&#xA;          { for (i = 1; i &amp;lt;= NF; i += 3)&#xA;              printf &amp;#34;0x%02X%02X%02X &amp;#34;, $i, $(i+1), $(i+2);&#xA;              printf &amp;#34;\n&amp;#34;&#xA;          }&#xA;        }&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Eseguendo lo script &lt;code&gt;img2css.awk&lt;/code&gt; sul file &lt;code&gt;ppm&lt;/code&gt; precedente si ottiene&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./img2css.awk square_10x10.ppm &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0x000000 0x000000 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0x000000 0x000000 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0x000000 0x000000 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0x000000 0x000000 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0x000000 0x000000 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0x000000 0x000000 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0x000000 0x000000 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0x000000 0x000000 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0x000000 0x000000 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0x000000 0x000000 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0x000000 0x000000 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0x000000 0x000000 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Per riprodurre l&amp;rsquo;output prodotto da &lt;code&gt;img2css&lt;/code&gt;, è sufficiente modificare leggermente il modo in cui lo script stampa i valori dei colori RGB, aggiungere la stampa della le coordinate di ciascun pixel e inserire le parti iniziali e finali del &lt;a href=&#34;http://www.w3schools.com/cssref/css3_pr_box-shadow.asp&#34;&gt;tag &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;&lt;/a&gt;, ottenendo&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#!/usr/bin/awk -f&#xA;&#xA;BEGIN   { out = sprintf(&amp;#34;&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;&amp;#34;);&#xA;          print out;&#xA;        }&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;che produce un output equivalente a quello di img2css&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./img2css_v2.awk square_10x10.ppm&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;div style&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;height:1px;width:1px;box-shadow:#000000 0 0px, #000000 1px 0px, #000000 2px 0px, #000000 3px 0px, #000000 4px 0px, #000000 5px 0px, #000000 6px 0px, #000000 7px 0px, #000000 8px 0px, #000000 9px 0px, #000000 0 1px, #000000 1px 1px, #000000 2px 1px, #000000 3px 1px, #000000 4px 1px, #000000 5px 1px, #000000 6px 1px, #000000 7px 1px, #000000 8px 1px, #000000 9px 1px, #000000 0 2px, #000000 1px 2px, #FFFFFF 2px 2px, #FFFFFF 3px 2px, #FFFFFF 4px 2px, #FFFFFF 5px 2px, #FFFFFF 6px 2px, #FFFFFF 7px 2px, #000000 8px 2px, #000000 9px 2px, #000000 0 3px, #000000 1px 3px, #FFFFFF 2px 3px, #FFFFFF 3px 3px, #FFFFFF 4px 3px, #FFFFFF 5px 3px, #FFFFFF 6px 3px, #FFFFFF 7px 3px, #000000 8px 3px, #000000 9px 3px, #000000 0 4px, #000000 1px 4px, #FFFFFF 2px 4px, #FFFFFF 3px 4px, #FFFFFF 4px 4px, #FFFFFF 5px 4px, #FFFFFF 6px 4px, #FFFFFF 7px 4px, #000000 8px 4px, #000000 9px 4px, #000000 0 5px, #000000 1px 5px, #FFFFFF 2px 5px, #FFFFFF 3px 5px, #FFFFFF 4px 5px, #FFFFFF 5px 5px, #FFFFFF 6px 5px, #FFFFFF 7px 5px, #000000 8px 5px, #000000 9px 5px, #000000 0 6px, #000000 1px 6px, #FFFFFF 2px 6px, #FFFFFF 3px 6px, #FFFFFF 4px 6px, #FFFFFF 5px 6px, #FFFFFF 6px 6px, #FFFFFF 7px 6px, #000000 8px 6px, #000000 9px 6px, #000000 0 7px, #000000 1px 7px, #FFFFFF 2px 7px, #FFFFFF 3px 7px, #FFFFFF 4px 7px, #FFFFFF 5px 7px, #FFFFFF 6px 7px, #FFFFFF 7px 7px, #000000 8px 7px, #000000 9px 7px, #000000 0 8px, #000000 1px 8px, #000000 2px 8px, #000000 3px 8px, #000000 4px 8px, #000000 5px 8px, #000000 6px 8px, #000000 7px 8px, #000000 8px 8px, #000000 9px 8px, #000000 0 9px, #000000 1px 9px, #000000 2px 9px, #000000 3px 9px, #000000 4px 9px, #000000 5px 9px, #000000 6px 9px, #000000 7px 9px, #000000 8px 9px, #000000 9px 9px;&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/div&amp;gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;perfettamente funzionante, come si può verificare inserendo pari pari il tag &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; ottenuto in un documento html (come questo):&lt;/p&gt;&#xA;&lt;div style=&#34;height:1px;width:1px;box-shadow:#000000 0 0px, #000000 1px 0px, #000000 2px 0px, #000000 3px 0px, #000000 4px 0px, #000000 5px 0px, #000000 6px 0px, #000000 7px 0px, #000000 8px 0px, #000000 9px 0px, #000000 0 1px, #000000 1px 1px, #000000 2px 1px, #000000 3px 1px, #000000 4px 1px, #000000 5px 1px, #000000 6px 1px, #000000 7px 1px, #000000 8px 1px, #000000 9px 1px, #000000 0 2px, #000000 1px 2px, #FFFFFF 2px 2px, #FFFFFF 3px 2px, #FFFFFF 4px 2px, #FFFFFF 5px 2px, #FFFFFF 6px 2px, #FFFFFF 7px 2px, #000000 8px 2px, #000000 9px 2px, #000000 0 3px, #000000 1px 3px, #FFFFFF 2px 3px, #FFFFFF 3px 3px, #FFFFFF 4px 3px, #FFFFFF 5px 3px, #FFFFFF 6px 3px, #FFFFFF 7px 3px, #000000 8px 3px, #000000 9px 3px, #000000 0 4px, #000000 1px 4px, #FFFFFF 2px 4px, #FFFFFF 3px 4px, #FFFFFF 4px 4px, #FFFFFF 5px 4px, #FFFFFF 6px 4px, #FFFFFF 7px 4px, #000000 8px 4px, #000000 9px 4px, #000000 0 5px, #000000 1px 5px, #FFFFFF 2px 5px, #FFFFFF 3px 5px, #FFFFFF 4px 5px, #FFFFFF 5px 5px, #FFFFFF 6px 5px, #FFFFFF 7px 5px, #000000 8px 5px, #000000 9px 5px, #000000 0 6px, #000000 1px 6px, #FFFFFF 2px 6px, #FFFFFF 3px 6px, #FFFFFF 4px 6px, #FFFFFF 5px 6px, #FFFFFF 6px 6px, #FFFFFF 7px 6px, #000000 8px 6px, #000000 9px 6px, #000000 0 7px, #000000 1px 7px, #FFFFFF 2px 7px, #FFFFFF 3px 7px, #FFFFFF 4px 7px, #FFFFFF 5px 7px, #FFFFFF 6px 7px, #FFFFFF 7px 7px, #000000 8px 7px, #000000 9px 7px, #000000 0 8px, #000000 1px 8px, #000000 2px 8px, #000000 3px 8px, #000000 4px 8px, #000000 5px 8px, #000000 6px 8px, #000000 7px 8px, #000000 8px 8px, #000000 9px 8px, #000000 0 9px, #000000 1px 9px, #000000 2px 9px, #000000 3px 9px, #000000 4px 9px, #000000 5px 9px, #000000 6px 9px, #000000 7px 9px, #000000 8px 9px, #000000 9px 9px;&#34;&gt;&lt;/div&gt;&#xA;&lt;h4 id=&#34;conclusioni&#34;&gt;Conclusioni&lt;/h4&gt;&#xA;&lt;p&gt;È chiaro che usare &lt;code&gt;convert&lt;/code&gt; ed &lt;code&gt;awk&lt;/code&gt; non risolve il problema di fondo, le immagini CSS generate rimangono comunque molto più grosse di quelle originali, ma almeno sono prodotte con poche righe di codice ed usando solo degli strumenti standard di Unix.&lt;/p&gt;&#xA;&lt;p&gt;Alcuni anni fa si parlava in senso negativo di &lt;a href=&#34;https://en.wikipedia.org/wiki/Software_bloat&#34;&gt;&lt;em&gt;bloatware&lt;/em&gt;&lt;/a&gt;, di quei programmi inutilmente grossi e tanto poco ottimizzati da richiedere grosse risorse hardware anche per svolgere funzioni relativamente semplici.&lt;/p&gt;&#xA;&lt;p&gt;A volte i programmatori dimenticano due concetti fondamentali della buona programmazione, cercare la semplicità e usare lo strumento più adatto per il compito specifico, e si perdono in inutili (e stucchevoli) esercitazioni di stile. Succede a chi propone banalmente di usare file CSS enormi al posto di semplici immagini grafiche, ma succede anche in tanti altri casi ben peggiori.&lt;/p&gt;&#xA;&lt;p&gt;A parte questo, il post è stato anche un&amp;rsquo;occasione per parlare di &lt;code&gt;awk&lt;/code&gt;, uno strumento poco conosciuto ma molto otente, in particolare quando si tratta di analizzare e trasformare dati contenuti in file di testo.&lt;/p&gt;&#xA;&lt;p&gt;Uno strumento che è diventato parte integrante da anni della mia routine di lavoro quotidiana. Sarebbe bello poterne riparlare.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>I limiti di Wordpress.com: generatori di siti web statici</title>
      <link>https://melabit.com/it/2014/08/09/i-limiti-di-wordpress-com-generatori-di-siti-web-statici/</link>
      <pubDate>Sat, 09 Aug 2014 06:00:00 +0000</pubDate>
      <guid>https://melabit.com/it/2014/08/09/i-limiti-di-wordpress-com-generatori-di-siti-web-statici/</guid>
      <description>&lt;p&gt;Come ho già scritto qualche giorno fa, ci sono letteralmente decine di &lt;a href=&#34;http://melabit.wordpress.com/2014/08/06/i-limiti-di-wordpress-com-una-nuova-piattaforma-per-il-blog/&#34;&gt;generatori di siti web statici&lt;/a&gt;, quasi quante sono le distribuzioni di Linux. Io nei miei bookmark ne ho una trentina.&lt;/p&gt;&#xA;&lt;p&gt;Come orientarsi in questa moltitudine?&lt;/p&gt;&#xA;&lt;p&gt;Per le distribuzioni di Linux esiste &lt;a href=&#34;http://distrowatch.com&#34;&gt;Distrowatch&lt;/a&gt;, un sito popolarissimo che cerca di classificarle tutte. Analogamente, esistono almeno due siti che cercano di elencare tutti i generatori di siti web statici: &lt;a href=&#34;https://www.staticgen.com/&#34;&gt;StaticGen&lt;/a&gt; e &lt;a href=&#34;http://staticsitegenerators.net/&#34;&gt;Static Site Generators&lt;/a&gt;.&#xA;L&amp;rsquo;approccio dei due è totalmente diverso anche se le informazioni riportate sono praticamente le stesse.&lt;/p&gt;&#xA;&lt;p&gt;Il primo ordina di default i generatori di siti statici in base alla popolarità, ma si possono applicare vari filtri basati sul linguaggio di programmazione, la valutazione degli utenti e persino gli &lt;em&gt;issue&lt;/em&gt;, i problemi riscontrati dagli utenti.&lt;/p&gt;&#xA;&lt;p&gt;L&amp;rsquo;altro è apparentemente una tabella ordinata alfabeticamente (in questo momento elenca ben 289 sistemi diversi!), ma cliccando sulle intestazioni si può ordinarla in base al linguaggio di programmazione, alla valutazione degli utenti o alla data in cui il sistema è stato aggiornato per l&amp;rsquo;ultima volta.&#xA;Quest&amp;rsquo;ultima è una informazione utilissima, se un sistema non è aggiornato da anni non vale la pena perderci tempo.&lt;/p&gt;&#xA;&lt;p&gt;Provando ad applicare un po&amp;rsquo; di filtri si copre che esiste perfino un generatore, &lt;a href=&#34;https://github.com/moebiuseye/skf&#34;&gt;StatiKiss Framework&lt;/a&gt;, basato su &lt;a href=&#34;http://www.gnu.org/software/bash/&#34;&gt;Bash&lt;/a&gt;, ma &lt;a href=&#34;http://skf.jeannedhack.org/&#34;&gt;il sito web ufficiale&lt;/a&gt; contenente la documentazione non risponde. In realtà esisteva un&amp;rsquo;altro sistema interessante basato su Bash, &lt;a href=&#34;http://nanoblogger.sourceforge.net/&#34;&gt;NanoBlogger&lt;/a&gt;, il cui sviluppo  è stato però sospeso all&amp;rsquo;inizio del 2013. Evidentemente Bash non va bene per sviluppare siti web.&lt;/p&gt;&#xA;&lt;p&gt;Si può trovare anche &lt;a href=&#34;https://github.com/nuex/zodiac&#34;&gt;Zodiac&lt;/a&gt;, un generatore di siti statici scritto in &lt;a href=&#34;http://en.wikipedia.org/wiki/AWK&#34;&gt;AWK&lt;/a&gt;, un linguaggio perfetto per la manipolazione di file di testo, sviluppato fra gli altri da &lt;a href=&#34;http://www.cs.princeton.edu/~bwk/&#34;&gt;Brian Kernighan&lt;/a&gt;, uno dei padri di Unix e del linguaggio C. A leggere il README Zodiac sembra semplice da usare, supporta markdown e la struttura delle directory in cui sono organizzati i documenti utilizzati per generare il sito è ragionevole.&#xA;Ma purtroppo la popolarità di Zodiac è scarsa, scarsissima. Si potrebbe di certo usare per un progetto personale e soprattutto per imparare, ma è impensabile volere sostituire Wordpress con qualcosa come Zodiac. A chi rivolgersi, dove cercare aiuto e documentazione se si volesse fare qualcosa di non previsto dal programmatore, ad esempio gestire un sistema di commenti?&lt;/p&gt;&#xA;&lt;p&gt;Fra i generatori di siti web statici ci sono persino due sistemi scritti in &lt;a href=&#34;http://www.microsoft.com/net&#34;&gt;.NET&lt;/a&gt;. Ma vogliamo farci veramente del male?&lt;/p&gt;&#xA;&lt;p&gt;Ma lasciamo perdere le curiosità. Quali sono invece i &lt;em&gt;top player&lt;/em&gt;? Quali sono i sistemi più popolari, più diffusi e, si spera, più affidabili? Facile, il primo in assoluto è &lt;a href=&#34;http://jekyllrb.com/&#34;&gt;Jekyll&lt;/a&gt;, un generatore sviluppato in &lt;a href=&#34;https://www.ruby-lang.org/en/&#34;&gt;Ruby&lt;/a&gt;, un linguaggio di programmazione che è più o meno la risposta giapponese a Python, molto diffuso per sviluppare applicazioni web.&#xA;Seguono &lt;a href=&#34;http://octopress.org/&#34;&gt;Octopress&lt;/a&gt; (un derivato &lt;em&gt;semplificato&lt;/em&gt; di Jekyll, il cui sviluppo però è fermo dal 2011), &lt;a href=&#34;http://blog.getpelican.com/&#34;&gt;Pelican&lt;/a&gt; in Python, &lt;a href=&#34;http://middlemanapp.com/&#34;&gt;Middleman&lt;/a&gt; ancora in Ruby e &lt;a href=&#34;http://hexo.io/&#34;&gt;Hexo&lt;/a&gt; in JavaScript.&lt;/p&gt;&#xA;&lt;p&gt;Ci sono comunque altri generatori interessanti, alcuni con nomi veramente curiosi, &lt;a href=&#34;http://ruhoh.com/&#34;&gt;Ruhoh&lt;/a&gt;, &lt;a href=&#34;http://hugo.spf13.com/&#34;&gt;Hugo&lt;/a&gt;, &lt;a href=&#34;http://picocms.org/&#34;&gt;Pico&lt;/a&gt;, &lt;a href=&#34;http://calepin.co/&#34;&gt;Calepin&lt;/a&gt;,  &lt;a href=&#34;http://www.droppages.com/&#34;&gt;DropPages&lt;/a&gt;, &lt;a href=&#34;https://pancake.io/&#34;&gt;Pancake&lt;/a&gt;, &lt;a href=&#34;http://anchorcms.com/&#34;&gt;Anchor CMS&lt;/a&gt;, &lt;a href=&#34;http://ringce.com/hyde&#34;&gt;Hyde&lt;/a&gt;, &lt;a href=&#34;https://sculpin.io/&#34;&gt;Sculpin&lt;/a&gt;, &lt;a href=&#34;http://www.htmly.com/&#34;&gt;HTMLy&lt;/a&gt;,&lt;a href=&#34;http://dropplets.com/&#34;&gt;Dropplets&lt;/a&gt;, &lt;a href=&#34;http://www.steve.org.uk/Software/chronicle/&#34;&gt;Chronicle&lt;/a&gt;. Esiste persino il venerabile (ha quasi 10 anni!) &lt;a href=&#34;http://www.dir2web.it/&#34;&gt;Dir2web&lt;/a&gt;, l&amp;rsquo;unico prodotto italiano che conosca.&lt;/p&gt;&#xA;&lt;p&gt;Non mancato anche i prodotti a pagamento come &lt;a href=&#34;http://getkirby.com/&#34;&gt;Kirby&lt;/a&gt; e &lt;a href=&#34;http://statamic.com/&#34;&gt;Statamic&lt;/a&gt;. O come &lt;a href=&#34;http://cactusformac.com/&#34;&gt;Cactus&lt;/a&gt;, che è pure specifico per il solo Mac.&lt;/p&gt;&#xA;&lt;p&gt;Per questi ultimi no grazie, il web nasce e deve rimanere multipiattaforma, sistemi sviluppati per uno specifico sistema operativo non mi vanno bene &lt;em&gt;a priori&lt;/em&gt;. E trovo pure irragionevole cercare di vendere questi prodotti: se devo pagare per Statamic, quanto dovrei dare agli sviluppatori di Apache? Sei uno sviluppatore e vuoi guadagnarci? Distribuisci gratis il prodotto, dimostra nei fatti che è buono, fai in modo che diventi il più popolare possibile e poi vendi il supporto. Cercare di vendere software come questi, che subiscono la concorrenza di sistemi equivalenti, gratuiti e di qualità analoga se non migliore, è veramente sciocco.&lt;/p&gt;&#xA;</description>
    </item>
  </channel>
</rss>
