Newsgroup: it.comp.os.linux.sys
Titolo: problema con "date"

Ciao a tutti,
sono alle prese con una stupidata in bash che mi sta facendo impazzire.
Via snmp mi faccio restituire una serie di date. Di queste date devo
estrarre la più recente e confrontarla con la data attuale, per
intraprendere eventualmente altre azioni.
La data mi arriva in formato "mm/gg/aaaa hh:mm:ss AM" (piuttosto che la
stessa cosa ma con PM). Avevo pensato di convertirla in timestamp unix e
fare la differenza fra i due valori, in modo da capire se ho superato la
mia soglia a cui devo fare riferimento.
Purtroppo sono fermo al confronto, perché non riesco a passare tutti i
parametri all'opzione -d di date.
Ecco i pezzi di script incriminati:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# data locale - ts unix
DATE=`date +'%s' -u`
# data remota
BES_LAST_SYNC=`snmpwalk -c mia.community -v 1 mio.ip
1.3.6.1.4.1.3530.5.30.1.61|awk -F"\"" '{print $2}'|sort -r |head -n 1`
# ts unix data remota
BES_DATE=`date +'%s' -u -d'($BES_LAST_SYNC)'`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
e a questo punto mi fermo, perché qua si incricca tutto.
In pratica. BES_DATE mi viene valorizzato SEMPRE come se gli avessi
passato le ore 00:00:00 del valore che mi arriva via snmp.
Ho provato anche a spezzare con cut i valori in singole variabili
(BES_MONTH, BES_DAY, etc etc), per poi passarli a date, ma il risultato
non cambia.
Sono sicuro che è una cazzata, ma proprio non riesco a venirne a capo.
Idee/suggerimenti?



Questo dovrebbe funzionare:
DATE=$(date +%s -u)
LAST_SYNC=$(date -d "${BES_LAST_SYNC}" +%s -u)
DIFF=$(( $LAST_SYNC - $DATE ))    # o similari

 DIFF=$(( $LAST_SYNC - $DATE ))    # o similari
Mitico, grazie mille!

 1.3.6.1.4.1.3530.5.30.1.61|awk -F"\"" '{print $2}'|sort -r |head -n 1`
Come ho fatto notare in un altro thread, sort in pipe con 
head è un /escamotage/ molto inefficiente; per trattare con
le date bisogna usare Perl.
Però, a scanso di polemiche, se i tuoi scopi non sono troppo
esigenti, va bene così.

 esigenti, va bene così.
:)

 le date bisogna usare Perl.
Domande:
1) perche` inefficiente?
2) e se non fossero date?
bye,
-- 
piergiorgio

 1.3.6.1.4.1.3530.5.30.1.61|awk -F"\"" '{print $2}'|sort -r |head -n 1`
Qui c'è un bug di cui mi sono accorto solo ora.
Tu supponi che la data sia nel formato mese/giorno/anno e 
che l'ordinameto che fa sort sia per date e vada dalla più 
recente aòlla più remota.
Ora sort non sa niente del formato delle date, sort ordina 
alfabeticamente. Inoltre i due ordinamenti coincidono se e 
solo se non vi sono date errate, il formato della data 
è anno/mese/giorno, il mese ed il giorno con due sono 
specificati con due cifre e l'anno o sempre con quattro 
cifre o sempre con due.
Per evitare questo casino consigliavo Perl.


Facebook: Massimo Bacilieri

 Innanzi tutto gli apici inversi sono obsoleti.
but, are you sure? 
Ma direi di no... entrambe le sintassi esistevano in ksh.
Il problema con gli apici inversi è invece che non possono essere
annidati, quindi (anche se è raro il caso in cui si annidano) tanto
vale non usarli e dimenticarsi che esistono.
-- 
echo onailimissaM | awk 'BEGIN { FS = "" }
{ for (i = NF; i >= 1; i-- )
  printf $i }'; echo

 2) e se non fossero date?
Allora nessum problema. I problemi nascono con le date e 
gli orari.
Il mio algoritmo funziona se il secondo campo è numerico e
si può adattare per stringhe. Ma se il secondo campo è una 
data fallisce miseramente perché awk non può trattare date.
Certo si può adattare usando il comando date della GNU per
convertire i campi numerici in formato UNIX ed evitare il
problema (come ha cercato di fare DeeepBlue) però in questo 
caso avresti una cosa assolutamente non portabile.
Solo il date della GNU permette di convertire una data 
qualsiasi, gli altri date permettono solo di trattare 
la data corrente. E non sono sicuro che tutti permettano 
di visualizzare la data in Formato Unix (cioè in secondi 
dalla Epoch)
In definitiva, meglio usare Perl che ha moduli apposta 
per le date.
 

 cifre o sempre con due.
Come dicevo prima, per design il formato dovrebbe essere sempre
mm/dd/yyyy hh:mm:ss X. Purtroppo non ho la specifica di cosa possa
passare il sw da cui recupero i dati via snmp.
In ogni caso questo script è un plugin per Nagios: se il sw comincia a
passarmi dati malformati, probabilmente c'è qualcosa che non va, il mio
script dice a Nagios che l'output ottenuto non è conforme (oppure va
direttamente in errore), con la conseguenza che Nagios (in entrambi i
casi) passa il service in stato critical e mi manda un alert.
Per fortuna non devo fare elaborazioni accurate di questi dati, quindi
posso tirare un po' il fiato con la bash (il perl mi piace molto, ma con
la bash per queste cose ci metto 1/4 del tempo - salvo problemi con il
comando date :P).

 per le date.
OK, thanks!
bye,
-- 
piergiorgio

 Ma direi di no... entrambe le sintassi esistevano in ksh.
Certo lo sapevo. In effetti la bash prende molte cose 
dalla Korn shell, non solo questo.
Errore mio.
 

 sia meglio awk.
In realta` sembra che gawk sia piuttosto efficiente.
Da una rapida prova, con una file di dimensione variabile
(100, 1000, 4000, 8000 record) e` risultato sempre il
doppio piu` veloce (meta` tempo) di sort + head.
bye,
-- 
piergiorgio

 ...
Trovo anche io che si un metodo ottimo e lo ho usato in passato.
Purtroppo non è portabile.

 dalla Korn shell, non solo questo.
I strongly agree. Questa è una di quelle cose mai dette, ma
assolutamente vera.


 E come bonus $(..) permette anche l'annidamento
Yes sir (oggi m'è preso con l'inglese):
$(...$(...)...) <--- funziona
`...`...`...` <---- sar_ca$$o_che_fa


 doppio piu` veloce (meta` tempo) di sort + head.
Ancora piu` interessante e` che sort da solo, sulla
lista pre-processata, e` veloce quanto gawk.
Cioe` non sembra che il problema sia nel fatto che
sort e` (o dovrebbe essere) O(n log(n)), ma nel pipe.
In particolare sort ... | head -1 e` veloce quanto
il codice gawk, mentre sort ... > /dev/null ci mette
il doppio del tempo (meta` velocita`).
Il problema sembrerebbe essere l'I/O, dato che head -1
termina immediatamente.
bye,
-- 
piergiorgio

 sort e` (o dovrebbe essere) O(n log(n)), ma nel pipe.
Prova con
sort -r -k 2 < $inputfile | head -n 1 | awk '{print $2}'
vedrai che saranno veloci uguali.
-- 
Flavio Visentin
Scientists have finally discovered what's wrong with the female brain:
On the left side, there is nothing right, and on the right side, there
is nothing left.

 `...`...`...` <---- sar_ca$$o_che_fa
Se fai
`....\`...\`....`
funziona, ma diventa rapidamente illeggibile (ammesso che cosi' sia
leggibile!). Molto meglio $(....) che gestisce bene anche gli apici
interni. Qui altri dettagli:
http://wooledge.org:8000/BashFAQ/082

 E come bonus $(..) permette anche l'annidamento
Questo è un bel vantaggio, invece, che in effetti mi sono sempre perso!


 vedrai che saranno veloci uguali.
No, questo e` il piu` lento di tutti, circa
un 15%~20% piu` lento della versione opposta.
A mio avviso perche` sort, pur ordinando per
un solo campo, deve processare tutta la linea.
Il che potrebbe far pensare che il problema
sia, in effetti, fare il parsing della linea
per trovare il campo...
Sia con sort che con gawk + sort + head.
Mentre gawk da solo, pur perdendo sul parsing,
guadagna sulla complessita` O(n).
Dimenticavo, il mio sort ha anche un "-n", ma
senza, risultato a parte, non cambia nulla di
realmente misurabile in termini prestazionali.
E nemmeno con "-g".
bye,
-- 
piergiorgio

 
miiinchia. Non per niente il link da te suggerito dice: 
It just gets uglier and uglier after two levels.  :-)


 funziona,
Minchia è vero (l'esempio è cretino e cervellotico, ma era per provare
con la prima cosa che mi veniva in mente):
~$ echo `date -d \`echo "2009-04-18"\``
Sat Apr 18 00:00:00 CEST 2009
Pensa che non l'ho mai provato, perché mi sembrava illogico: il
backslash usualmente "neutralizza" ogni significato funzionale di un
simbolo, per cui \` l'avrei inteso come un apice inverso "verbatim".
Mi sorprende scoprire che qui è diverso.


 date a mano (rispettando il formato), fin'ora sort non ha mai sbagliato.
sort applica un ordinamento lessicografico, non ha conoscenza che
quella stringa da te fornita contenga una data;
Il formato che usi ( mm/dd/yyyy ... ) va benissimo finchè tutte le
date hanno lo stesso anno.
E' però facile verificare che tra 01/01/2009 (primo gennaio) e
12/31/2008 (31 dicembre) sort affermerà che la più recente è
quest'ultima.

 ha scritto:

in realtà ne verresti a capo combinando un paio di volte:
"-t" field separator
"-k" campo da considerare
Prima li ordini per anno (seguendo il tuo esempio: sort -t/ -k3), ... a
questo punto ho l'impressione che sort sia più intelligente di quel che
sembra (quindi non è necessario fare ulteriori passaggi).
ad esempio:
echo -e "12/24\n13/10\n1/10"|sort -t/ -k2
sort, dopo aver ordinato per il secondo campo, prende 1/10 e lo mette
in cima. 


 in cima. 
Confermo. -t / -k3 bypassa anche il problema di san silvestro.
Grazie ancora a tutti
 

 Grazie ancora a tutti
Che palle. In realtà poi mi si incasina con l'ora.
Mi sa che faccio prima a convertire tutto con timestamp unix e a fare
sort su quello. Oppure, appunto, a rifare tutto in perl... :(

 sort su quello. Oppure, appunto, a rifare tutto in perl... :(
Se non devi portarlo in giro su n diverse
versioni di *nix, direi che usare il
timestap in secondi e` la cosa piu` facile.
bye,
-- 
piergiorgio

 timestap in secondi e` la cosa piu` facile.
Proprio questo non si può fare perchè non è 
portabile.


Ed io cosa ho scritto?
bye,
-- 
piergiorgio

 Ed io cosa ho scritto?
Che io debba consultare un oculista?
Scusa ho letto male.

 Scusa ho letto male.
Figurati, succede anche a me... Spesso...
bye,
-- 
piergiorgio

Il giorno Sun, 19 Apr 2009 10:47:47 +0200
DeepBlue <deep...@spam.is.lame> ha scritto:

e va bene... prova a cambiare il field separator e a fare una seconda
passata di sort (parlo in linea teorica, perché adesso non ho voglia di
cimentarmi).
Comunque, non sono un asso del perl, ma confermo che in questo caso è
più efficiente: sa già come fare il sort del "time"
Mi pare che gli si dice una cosa tipo: stfrtime blabla .... l'ho fatto
un paio di mesi fa e non mi ricordo più.
