Quasi tutti hanno bisogno di gestire un'agenda con i propri impegni, e farlo con un computer è effettivamente una bella comodità. Non tutti però sono dell'idea di usare quella che al momento è la soluzione standard, google calendar, e condividere i propri impegni personali con una multinazionale, NSA, FBI e i loro amici.

Esistono soluzioni simili a google calendar installabili su un proprio server, ma a volte cambiare approccio e riguardare come si facevano le cose una volta può presentare piacevoli sorprese.

I vecchi unix comprendevano un programma, calendar, attualmente presente nelle bsdmainutils, che semplicemente legge un file in cui ogni riga inizia con una data, e stampa le righe corrispondenti alla data odierna o di qualche altro giorno. Per molte persone questo comportamento è sufficiente a gestire un'agenda: chi non deve incastrare meeting ad ogni ora del giorno, ma si limita ad uno o due impegni può lanciare quel comando ad ogni login (o ad ogni apertura di una shell) e avere sempre sottocchio quel che deve fare, senza far fatica o ricordarsi di consultare altri programmi.

calendar è però vecchiotto e limitato: è possibile indicare impegni per un giorno ben preciso, e poco più; non ha supporto per eventi ricorrenti, o calcoli complicati per specificare le date, né permette output diverso dalla semplice stampa delle righe inserite.

A questo pone rimedio remind, un'evoluzione dell'idea di calendar che ne supera le limitazioni tramite un linguaggio di scripting in grado di esprimere in poche righe anche regole complesse.

Ciao, mondo!

Partiamo dal caso più semplice: il 21 giugno 2013 vogliamo salutare il mondo:

$ echo 'REM 21 Jun 2013 MSG Ciao, mondo!' > ~/.my_reminders
$ remind .my_reminders 2013-06-21
Reminders for Friday, 21st June, 2013:

Ciao, mondo!

Il comando REM introduce un evento ed è seguito da un trigger, in questo caso la data, scritta esplicitamente, e da un'azione: MSG, che stampa il resto della riga come messaggio.

Il programma remind, lanciato con il nome del programma su cui lavorare ed una data, cerca tutti i messaggi il cui trigger sia valido in quella data e agisce su di essi, in questo caso stampandoli. Ovviamente tralasciando la data si suppone la data odierna.

Sintassi

Stampare un messaggio in una data precisa era ovviamente già possibile con il vecchio calendar, remind aggiunge nuove capacità significative.

Innanzitutto, è possibile decidere per ogni evento con quanti giorni di preavviso si vuole essere avvisati:

REM 28 Jun 2013 +7 MSG Evento che richiede preparazione %b.

in questo modo l'evento verrà stampato tutti i giorni a partire dal 21 luglio, con il numero di giorni mancanti al posto di %b.

Gli eventi ricorrenti sono il pane quotidiano di remind: partiamo da un caso semplice, un evento che capita a giorni della settimana fissi:

REM Wed MSG Riunione GL-Como.

Se si indica sia un giorno della settimana che una data, remind cerca il primo giorno di quel tipo che cade dopo la data (compresa); ad esempio il quarto sabato del mese è il primo sabato che cade dal 22 in poi:

REM Sat 22 Oct MSG Linux Day!

L'ultimo del mese si può indicare invece usando --n per andare indietro di n giorni:

REM Sun 1 Nov --7 MSG Passaggio all'ora solare.

Remind ha anche la capacità di gestire elenchi di giorni festivi nei quali alcuni eventi possono essere saltati o rimandati:

OMIT 25 Dec MSG Natale.
REM Wed SKIP MSG Riunione GL-Como.

No, quest'anno non faremo riunione il giorno di Natale :) ma potremmo sempre decidere di spostarla indietro:

REM Wed BEFORE MSG Riunione GL-Como

o avanti al primo giorno non festivo:

OMIT 26 Dec MSG Santo Stefano.
REM Wed AFTER MSG Riunione GL-Como.

Il comando

Oltre alla stampa degli eventi per un certo giorno, il comando remind permette di stampare calendari; con l'opzione -c si ottiene un calendario stampato sul terminale:

$ remind -c -w70 .my_reminders 2013-12-01
+--------------------------------------------------------------+
|                        December 2013                         |
+--------+--------+--------+--------+--------+--------+--------+
| Sunday | Monday |Tuesday |Wednesda|Thursday| Friday |Saturday|
+--------+--------+--------+--------+--------+--------+--------+
|1       |2       |3       |4       |5       |6       |7       |
|        |        |        |        |        |        |        |
|        |        |        |Riunione|        |        |        |
|        |        |        |GL-Como.|        |        |        |
|        |        |        |        |        |        |        |
|        |        |        |        |        |        |        |
|        |        |        |        |        |        |        |
+--------+--------+--------+--------+--------+--------+--------+
|8       |9       |10      |11      |12      |13      |14      |
|        |        |        |        |        |        |        |
|        |        |        |Riunione|        |        |        |
|        |        |        |GL-Como.|        |        |        |
|        |        |        |        |        |        |        |
|        |        |        |        |        |        |        |
|        |        |        |        |        |        |        |
+--------+--------+--------+--------+--------+--------+--------+
|15      |16      |17      |18      |19      |20      |21      |
|        |        |        |        |        |        |        |
|        |        |        |Riunione|        |        |        |
|        |        |        |GL-Como.|        |        |        |
|        |        |        |        |        |        |        |
|        |        |        |        |        |        |        |
|        |        |        |        |        |        |        |
+--------+--------+--------+--------+--------+--------+--------+
|22      |23      |24      |25      |26      |27      |28      |
|        |        |        |        |        |        |        |
|        |        |        |Natale. |        |        |        |
|        |        |        |        |        |        |        |
|        |        |        |        |        |        |        |
|        |        |        |        |        |        |        |
|        |        |        |        |        |        |        |
+--------+--------+--------+--------+--------+--------+--------+
|29      |30      |31      |        |        |        |        |
|        |        |        |        |        |        |        |
|        |        |        |        |        |        |        |
|        |        |        |        |        |        |        |
|        |        |        |        |        |        |        |
|        |        |        |        |        |        |        |
|        |        |        |        |        |        |        |
+--------+--------+--------+--------+--------+--------+--------+

mentre l'opzione -p ed un altro programma incluso nel pacchetto, rem2ps, si può ottenere un file postscript:

$ remind -p .my_reminders 2013-12-01 | rem2ps | ps2pdf - 2013-december.pdf

genera il file 2013-december.pdf con un calendario del mese di dicembre.

Altre opzioni utili sono -k, che permette di passare i messaggi ad un programma; ad esempio per aprire un pop-up per ogni evento:

$ remind '-knotify-send %s' .my_reminders

L'opzione -z permette invece di far andare remind in modalità demone, agendo sugli eventi man mano che questi diventano attivi.

Sintassi avanzata

Remind permette di fare molto di più; la wiki comprende alcune ricette copiabili ed altre fonti di ispirazione, ed altre idee si possono trovare coi motori di ricerca, oppure si può leggere la pagina di manuale e scoprire tutte le potenzialità del programma.

Per fare qualche esempio delle potenzialità di remind, questo snippet stampa sorgere e tramontare del sole per Como, e la prossima luna nuova o piena:

SET $Location "Como"
SET $LatDeg 45
SET $LatMin 48
SET $LatSec 43
SET $LongDeg 9
SET $LongMin 50
SET $LongSec 2

REM MSG Ephemerides for [today()] in [$Location]:%
REM MSG   sunrise at [sunrise()], sunset at [sunset()]%
IF moonphase() <= 180
   REM MSG   next full moon on [wkday(moondate(2))], [moondatetime(2)]
ELSE
   REM MSG   next new moon on [wkday(moondate(0))], [moondatetime(0)]
ENDIF

per farlo fa uso di variabili standard (per impostare latitudine e longitudine), funzioni builtin e controllo di flusso. Questo è il risultato per il 22 giugno:

$ remind .my_reminders 
Reminders for Saturday, 22nd June, 2013 (today):

Ephemerides for 2013-06-22 in Como:
  sunrise at 06:54, sunset at 22:37
  next full moon on Sunday, 2013-06-23@13:33

Un altro esempio, che sarebbe molto utile alle cene pre-riunione, fa visualizzare un pop-up quando è ora di finire di cenare e andare ad aprire la sede:

REM Wed AT 20:50 RUN notify-send "Riunione imminente!" "Smettere subito di strafogarsi"

salvato come riunioni.rem, viene poi letto dal comando:

$ remind -z riunioni.rem

Sincronizzazione e condivisione

Fedele ai principi di Unix, remind non ha funzionalità specifiche per la sincronizzazione tra più computer o la condivizione dei calendari, ma il suo formato puramente testuale si presta particolarmente bene all'uso di strumenti già esistenti.

Per condividere un calendario tra più persone è sufficiente condividere un file tra più persone con qualsiasi metodo (disco comune, cartelle condivise, cartelle condivise tramite server, WebDav...) che permetta di assegnare a ciascuno i permessi voluti; per includere questi eventi nel proprio calendario basterà includerne il file.

Lo stesso principio si applica alla sincronizzazione tra più dispositivi; in particolare degno di nota è il fatto che il formato di remind è facile da gestire in un sistema di controllo di revisioni.

Ad esempio con git una persona può avere un repository con i file della sua agenda, sincronizzato tra i vari dispositivi in uso. Un gruppo di persone che deve condividere un calendario può poi creare un repository aggiuntivo che ciascuno aggiungerà come sottomodulo nel suo repository principale.

Inoltre esistono degli script che forniscono interoperabilità con il formato iCalendar: rem2ics e ical2remrrb, utili ad interfacciarsi con il resto del mondo.

Per i dispositivi sui quali remind non è (ancora?) disponibile si può altrimenti usare un cgi che permette di accedere ad una versione html del proprio calendario: remindccgi.

Front-end

Per chi non vuole impararsi la sintassi di remind, sono state sviluppate alcune interfacce più o meno grafiche; gli autori stessi includono tkremind (screenshot di tkremind).

Altri frontend scritti da terze parti includono wyrd, scritto in curses con interfaccia ispirata a mutt, e wxRemind, grafico.

Per approfondire

David Skoll ha scritto un articolo su Linux Journal nel quale presenta remind entrando anche nei dettagli della sintassi.

Ulteriori informazioni si possono trovare sulla wiki e sulla mailing list dedicata agli utenti ed appassionati del programma, dove è anche possibile ottenere aiuto per i calcoli più complicati.

La documentazione completa è comunque presente nella pagina di manuale.