Cosa dice la tua .bash_history?

Un mio amico mi ha detto che sui blog tecnici gira un nuovo meme: mostrare i comandi più usati, partendo dalla history della shell:

history | \
awk '{a[$2]++}END{for(i in a){print a[i] " " i}}' | \
sort -rn | head -15

Io ho 20 volte la dimensione di default della bash history (10k righe), quindi i risultati saranno interessanti. Uso anche la funzione di timestamp della history, quindi ho aggiunto un piccolo sed al codice per eliminare i timestamp.

Vediamo un po':

vjt@voyager:~/code*$* history | 
 sed 's#^[ 0-9\[\/\:]*\]\([^ ]*\).*#\1#' |  
 awk '{a[$1]++}END{for(i in a){print a[i] " " i}}' | 
 sort -rn | head -15
928 l
577 ssh
389 ping
381 cd
300 dig
259 telnet
153 sudo
126 ifconfig
125 whois
113 ps
96 svn
91 cat
73 fg
68 vi
61 ..

Già, faccio un SACCO di ls, l in realtà è ls -alFGs (sono su Darwin). Questa lista rivela le mie abitudini recenti, perché sto scrivendo meno codice e gestendo di più (niente gcc, niente irb, un sacco di dig & whois). svn è ancora lì, ovviamente ;). ssh significa che questi risultati andrebbero aggregati con le history delle altre macchine su cui mi loggo… ma quello è argomento per un altro post ;).

Quali sono i tuoi risultati?

Postali qui! :D

AGGIORNAMENTO 2008-06-03

Dato che le mie abitudini recenti sono più di coding che di scrittura di documentazione, ho rieseguito l’analisi della history… e questi sono i nuovi risultati:

1796 l
981 svn
705 ssh
693 cd
666 ping
402 vi
356 ifconfig
352 telnet
321 dig
315 sudo
283 fg
240 grep
188 ..
183 cat
157 ps

AGGIORNAMENTO 2009-02-20

5427 l
4379 git
3128 svn
2812 vi
2105 cd
1408 ping
1392 fg
1328 ssh
935 ifconfig
893 grep
890 sudo
733 rake
653 cat
554 ..
535 ruby

AGGIORNAMENTO 2009-05-24

7374 l
5041 git
3265 vi
3131 svn
2753 cd
1881 ssh
1763 ping
1618 fg
1101 sudo
1100 ifconfig
977 grep
867 cat
767 rake
721 telnet
671 ..

AGGIORNAMENTO 2010-06-01

20517 git
7794 l
1906 cd
1631 rg
1518 vi
1108 rake
1041 cat
1010 ruby
790 sudo
754 fg
676 make
670 script/console
626 rm
496 ping
474 ..

AGGIORNAMENTO 2012-07-23

3367 l
2685 ssh
1289 cd
1013 curl
976 git
857 sudo
815 ping
526 telnet
521 ps
497 cat
472 port
422 fg
400 vi
274 rm
259 dig
📜

Questo articolo è stato scritto nel 2008. È qui per ragioni storiche — i dettagli tecnici potrebbero non essere più validi.

🔍
Retrospettiva 2026
LightWindow è morto da un pezzo – era una libreria modale dell’era Prototype.js, scomparsa intorno al 2010. Se oggi ti servono le modali, l’elemento HTML <dialog> fa tutto nativamente.

Ecco, questo è il risultato di 2 giorni di testate contro il muro con lightwindow:

Index: public/javascripts/lightwindow.js, line 444

  _removeLink : function(removed) {
    // remove it from the links array
    //
    this.links = this.links.reject(function(link) {
      if (link == removed.href)
        return true;
    });
    // remove it from the gallery links array
    //
    if (gallery = this._getGalleryInfo(removed.rel)) {
      klass = gallery[0];
      name = gallery[1];
      if (this.galleries[klass] && this.galleries[klass][name]) {
        this.galleries[klass][name] = 
          this.galleries[klass][name].reject(function(link) {
            if (link == removed.href)
              return true;
          });
      }
    }
  },

Chiama questa funzione dal tuo template .rjs, qualcosa tipo:

page << "myLightWindow._removeLink($('element').down('a.lightwindow'));"

Più dettagli a seguire, quando questo lavoro sarà completo ;).

Sappiamo ancora farlo

Beh, a quanto pare non ho motivo di essere paranoico per la mia età: so ancora andare in inline come facevo (ogni giorno) quando ero un po’ più giovane :).

Il primo maggio, festa dei lavoratori, Sam mi ha letteralmente trascinato fuori di casa, lontano dal computer, e siamo andati a pattinare. È stata una giornata fantastica, abbiamo pattinato un sacco e scattato delle belle foto.

Ma quelle davvero belle sono state scattate quando ndstr ci ha beccati. È di gran lunga il miglior fotografo che tu possa incontrare, e ovviamente il mio preferito (dai un’occhiata al suo sito!).

Anche lui è stato un pattinatore, quindi sa benissimo come e quando scattare per tirare fuori il massimo dai tuoi trick :). Eccone due, che ritraggono me e Sam mentre diamo il meglio!

Foto di skating

È stato divertente. Davvero divertente. Grazie Sam per avermi portato fuori di casa :D.

Oh, e non dimenticare di visitare il mio deviantArt, e guarda questa qui :D

📜

Questo articolo è stato scritto nel 2008. È qui per ragioni storiche — i dettagli tecnici potrebbero non essere più validi.

🔍
Retrospettiva 2026
Il recovery in single-user mode (Cmd-S, fsck, mount in scrittura) descritto qui non funziona più sui Mac moderni. Apple ha rimosso la modalità single-user in macOS Catalina (2019), il volume di sistema è diventato read-only con il Signed System Volume in Big Sur (2020), e i Mac Apple Silicon usano un’architettura di recovery completamente diversa.

Beh, sono davvero contento di OSX 10.5.2. Anche se non sono uno di quelli che ha insultato Apple per la barra dei menu traslucida che a tutti fa schifo… anzi, a me piace. Non mi interessa il tool di TM nella barra dei menu, perché non ho (ancora) comprato la fighissima Time Capsule, mi piace lo spinner nel menu Airport e, soprattutto, apprezzo molto gli aggiornamenti al BluetoothSCOAudioDriver.kext che pilota il mio auricolare bluetooth.

Spotlight sembra anche più veloce ad ogni aggiornamento, e sono un utente pesante di Spotlight, quindi questo mi rende davvero felice. Grazie ingegneri Apple!

Ma torniamo al tema: perché odissea? Perché seguendo i miei consigli sulla batteria, sono riuscito a far SPEGNERE il mio MacBook2,1 mentre era al 74% della fase “Scrittura file” del combo update… risultato: un sistema completamente distrutto, come ogni geek potrebbe immaginare :). Apple aveva aggiornato alcune librerie, e al riavvio semplicemente niente funzionava, e la console Darwin era piena di tonnellate di messaggi di errore.

Il tipico fanb^Wutente Apple avrebbe semplicemente archiviato e reinstallato il sistema, ma ehi, io sono un geek orgoglioso! So per esperienza che le situazioni di disaster recovery sono le migliori per imparare qualcosa su un sistema operativo, perché devi aiutare il sistema ad avviarsi, tirando su i servizi a mano, e trovare un modo per riapplicare il combo update senza usare la comoda interfaccia Aqua.

Google Maps (parte I de "Il Googling")

Ti sei mai preoccupato di Google Maps e di quanto quell’app riesca a vedere della tua casa, della tua auto, dei tuoi vicini e… forse… di te stesso?!?

Beh, forse hai ragione! Dai un’occhiata a questo video dei the vacationeers

;D

📜

Questo articolo è stato scritto nel 2008. È qui per ragioni storiche — i dettagli tecnici potrebbero non essere più validi.

🔍
Retrospettiva 2026
Questi consigli sono ormai l’opposto di quel che Apple raccomanda. Le batterie al litio moderne si degradano più in fretta con i cicli di scarica completa. Da macOS Catalina (2019), la “Ricarica ottimizzata della batteria” si ferma automaticamente all'80%. Apple consiglia di tenere il MacBook collegato quando possibile e ha rimosso la guida sulla “calibrazione tramite scarica completa” intorno al 2012.

3 semplici regole:

  • NON lasciare il caricatore collegato quando la batteria è carica, neanche quando vai a dormire.

  • LASCIA che si scarichi completamente: quando lo usi aspetta che arrivi allo 0%, quando vai a dormire lascialo lì; quando ti sveglierai e lo aprirai, un bel resume da suspend to disk ti darà il buongiorno. OSX FTW.

  • Monitorala e fai vedere i contatori di performance di OSX ai tuoi amici (immagini per gentile concessione di CoconutBattery.app e System Profiler.app)

Salute della batteria Cicli della batteria

📜

Questo articolo è stato scritto nel 2008. È qui per ragioni storiche — i dettagli tecnici potrebbero non essere più validi.

🔍
Retrospettiva 2026
Sun è stata acquisita da Oracle nel 2010 e Solaris è di fatto abbandonato da quando Oracle ha smantellato il team nel 2017. Python 2.4 e urllib2 non esistono più — urllib2 è stato incorporato in urllib.request in Python 3.

Mentre installavo allegramente i prerequisiti per compilare un’applicazione su Solaris 11, ho apprezzato il fatto di trovare Mercurial già installato nel sistema base… tranne per un GROSSO problema: la digest authentication era rotta. Ho fatto un tcpdump del traffico scambiato tra il client Mercurial e il server CGI e ho visto che non veniva inviato nessun header Authorization, e ovviamente il server si rifiutava di servire il repository hg.

Prima di reinstallare Python, magari da sorgente e sostituendo l’installazione di default oppure tenendo affiancate due versioni diverse, con le conseguenti seccature e sporcizia nel sistema, ho provato un patch davvero minuscolo a urllib2.py che… con mio divertimento, ha risolto il problema:

--- urllib2.py~ Fri Jan 25 02:35:59 2008
+++ urllib2.py  Fri Jan 25 03:27:52 2008
@@ -815,7 +815,7 @@
             auth_val = 'Digest %s' % auth
             if req.headers.get(self.auth_header, None) == auth_val:
                 return None
-            req.add_unredirected_header(self.auth_header, auth_val)
+            req.add_header(self.auth_header, auth_val)
             resp = self.parent.open(req)
             return resp

Non sono un ca**o di esperto Python (ma il linguaggio è interessante), quindi non chiedetemi PERCHÉ funziona: ho semplicemente seguito il commento di add_header che diceva “questo metodo è utile per aggiungere header di autenticazione” e ho sostituito il metodo unredirected_header con il primo. Non ho proprio idea del perché con urllib2 di Python2.5 “tutto funziona” anche con quel metodo; qualcosa deve essere rotto da qualche altra parte. Un diff tra le due urllib non mi ha dato niente, dovrei davvero imparare Python prima o poi.

Active Gibberish

📜

Questo articolo è stato scritto nel 2008. È qui per ragioni storiche — i dettagli tecnici potrebbero non essere più validi.

🔍
Retrospettiva 2026
Il plugin Gibberish e tutto questo approccio sono morti e sepolti. Rails 2.2 (2008) ha aggiunto il supporto I18n integrato, e da Rails 3 in poi il modo standard è config/locales/*.yml con la gem i18n. I messaggi di errore di ActiveRecord, i nomi dei campi e tutte le stringhe dell’interfaccia sono gestiti nativamente — niente plugin, niente monkey-patching.

AGGIORNAMENTO: non ti serve questo codice, perché a partire dalla versione 2.2 di Rails il supporto alla localizzazione è integrato.

Localizzazione dei messaggi di errore di Active Record

Oggi ho dovuto rispondere a una delle domande su cui ogni sviluppatore Rails non anglofono prima o poi inciampa… come localizzare i messaggi di errore di AR per mostrarli in modo decente a un cliente che non parla inglese ;).

Prima di tutto, grazie all’eccellente plugin gibberish di defunkt e al modo in cui gli errori di validazione di AR sono esposti, il compito è stato portato a termine in modo semplice e pulito, senza mettere troppo le mani negli internals di AR.

Ho cominciato traducendo ogni messaggio di errore predefinito di AR, con questo file di traduzione in lang/it.yml:

# Active Record errors
#
ar_accepted:     "deve essere accettato" 
ar_not_a_number: "non è un numero" 
ar_blank:        "è un campo obbligatorio" 
ar_empty:        "è un campo obbligatorio" 
ar_inclusion:    "non è nella lista dei valori validi" 
ar_too_long:     "è troppo lungo (massimo %d caratteri)" 
ar_exclusion:    "è riservato" 
ar_too_short:    "è troppo corto (minimo %d caratteri)" 
ar_invalid:      "non è valido" 
ar_wrong_length: "è errato, dovrebbe essere di %d caratteri" 
ar_confirmation: "non corrisponde" 
ar_taken:        "esiste già" 
# This one is not a default key, but I use it in my validations
ar_greater_zero: "deve essere maggiore di zero" 

e quattro righe in config/environment.rb:

Estrarre dati dalla cache di Apple Safari

📜

Questo articolo è stato scritto nel 2008. È qui per ragioni storiche — i dettagli tecnici potrebbero non essere più validi.

🔍
Retrospettiva 2026
Safari ha abbandonato questo formato di cache SQLite anni fa. Più o meno da Safari 10 / macOS Sierra (2016), la cache è stata spostata in com.apple.WebKit.Networking in un formato blob binario — il vecchio Cache.db non esiste più.

Cinque minuti fa ho sovrascritto il nuovissimo e fiammante foglio di stile CSS che implementa la combinazione di colori attuale, perché volevo ripristinare quello originale e metterlo in un nuovo tema per questo sito, così che chi apprezzava il vecchio tema potesse continuare a usarlo. Ma, come il più principiante degli amministratori di sistema, ho decompresso i file originali dall’archivio di backup SOPRA quelli attuali…

Safari in soccorso! Ogni elemento nella cache di Safari è memorizzato in un database SQLite3 che si trova in ~/Library/Caches/com.apple.Safari, andiamo a vedere com’è strutturato:

 13:54:42 vjt@voyager:~/Library/Caches/com.apple.Safari$ sqlite3 Cache.db 
SQLite version 3.5.1
Enter ".help" for instructions

sqlite> .tables
cfurl_cache_blob_data       cfurl_cache_schema_version
cfurl_cache_response      

sqlite> .schema cfurl_cache_response 
CREATE TABLE cfurl_cache_response(
  entry_ID INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
  version INTEGER,
  hash_value INTEGER,
  storage_policy INTEGER,
  request_key TEXT UNIQUE,
  time_stamp NOT NULL DEFAULT CURRENT_TIMESTAMP);

sqlite> .schema cfurl_cache_blob_data
CREATE TABLE cfurl_cache_blob_data(
  entry_ID INTEGER PRIMARY KEY,
  response_object BLOB,
  request_object BLOB,
  receiver_data BLOB,
  proto_props BLOB,
  user_info BLOB);

sqlite> select * from cfurl_cache_response limit 3;
1|0|1897220634|0|http://..../|2008-01-19 11:10:33
2|0|-662909776|0|http://..../|2008-01-19 11:10:33

Wow. Impressionante. Ecco perché adoro i prodotti Apple: sono così ben strutturati che puoi liberamente ispezionarli e usare le loro risorse per qualsiasi compito imprevisto tu debba completare… anche per rimediare ai tuoi stessi errori ;). Ed è anche stimolante, perché devi rimboccarti le maniche e trovare la soluzione esplorando un prodotto software costruito splendidamente.


In questa pagina