2009-12-03 12 views
39

Come si analizza una data in bash, con campi separati (anni, mesi, giorni, ore, minuti, secondi) in diverse variabili?Parse Date in Bash

Il formato della data è: YYYY-MM-DD hh:mm:ss

risposta

52

ha a essere bash? È possibile utilizzare la GNU coreutils /bin/date binario per molte trasformazioni:

$ date --date="2009-01-02 03:04:05" "+%d %B of %Y at %H:%M and %S seconds" 
02 January of 2009 at 03:04 and 05 seconds 

Questo analizza la data indicata e lo visualizza nel formato scelto. Puoi adattarlo a piacere alle tue esigenze.

+6

È un'estensione Linux? Né FreeBSD o Mac OSX sembrano supportarlo. –

+1

E 'semplice vecchia data GNU: $ data --version data (coreutils GNU) 7.4 Copyright (C) 2009 Free Software Foundation, Inc. licenza GPLv3 +: GNU GPL versione 3 o successiva . Questo è un software gratuito: sei libero di cambiarlo e ridistribuirlo. Non c'è NESSUNA GARANZIA, nella misura consentita dalla legge. Scritto da David MacKenzie. –

+0

Perché 'date --date =" \ 'date \' "' non funziona? – Luc

6
$ t='2009-12-03 12:38:15' 
$ a=(`echo $t | sed -e 's/[:-]/ /g'`) 
$ echo ${a[*]} 
2009 12 03 12 38 15 
$ echo ${a[3]} 
12 
+2

non è necessario chiamare il comando esterno – ghostdog74

0

hai provato a tagliare? qualcosa di simile: dayofweek = date|cut -d" " -f1

+0

Questo separa solo la data e l'ora, non ciascuna parte singolarmente. –

2

Pure Bash:

date="2009-12-03 15:35:11" 
saveIFS="$IFS" 
IFS="- :" 
date=($date) 
IFS="$saveIFS" 
for field in "${date[@]}" 
do 
    echo $field 
done 

2009 
12 
03 
15 
35 
11 
+0

Non è necessario utilizzare gli array qui. Basta impostare $ junk; shift' invece di 'date = ($ date)' e 'for field' invece del ciclo di array. Questa sarebbe una versione 'pura sh', che è ancora meglio! – Idelic

1

un altro bash pura

$ d="2009-12-03 15:35:11" 
$ d=${d//[- :]/|} 
$ IFS="|" 
$ set -- $d 
$ echo $1 
2009 
$ echo $2 
12 
$ echo [email protected] 
2009 12 03 15 35 11 
3

Il metodo array è forse meglio, ma questo è quello che stavi chiedendo esplicitamente di:

IFS=" :-" 
read year month day hour minute second < <(echo "YYYY-MM-DD hh:mm:ss") 
+1

Mi piace di più. Una scorciatoia, che non modifica in modo permanente IFS: 'IFS =": - "leggi Y M D h m s <<<" AAAA-MM-GG hh: mm: ss "' – ephemient

25

Questo è semplice, basta convertire i trattini e due punti in uno spazio (non c'è bisogno di cambiare IFS) e usare 'leggere' tutto su una riga:

read Y M D h m s <<< ${date//[-:]/ } 

Ad esempio:

$ date=$(date +'%Y-%m-%d %H:%M:%S') 
$ read Y M D h m s <<< ${date//[-: ]/ } 
$ echo "Y=$Y, m=$m" 
Y=2009, m=57 
2

invece di utilizzare il shell scripting, incorporare nella vostra stessa scripting come di seguito wheever è necessario:

a=date +%Y 
b=date +%S 
c=date +%H 

un anno sarà b sarà secondi C saranno ore. e così via.

2

Un'altra soluzione al problema del PO:

IFS=' -:' read y m d h m s<<<'2014-03-26 16:36:41' 

Conversione di una data in un altro formato con BSD date e GNU date:

$ LC_ALL=C date -jf '%a %b %e %H:%M:%S %Z %Y' 'Wed Mar 26 16:36:41 EET 2014' +%F\ %T 
2014-03-26 16:36:41 
$ gdate -d 'Wed Mar 26 16:36:41 EET 2014' +%F\ %T 
2014-03-26 16:36:41 

GNU date riconosce Wed e Mar anche in non- Localizzazione inglese ma BSD date no.

Conversione secondi dal periodo ad una data e ora con data ed BSD GNU data:

$ gdate -d @1234567890 '+%F %T' 
2009-02-14 01:31:30 
$ date -r 1234567890 '+%F %T' 
2009-02-14 01:31:30 

Conversione secondi ore, minuti e secondi con un guscio POSIX POSIX awk, GNU date e BSD date :

$ s=12345;printf '%02d:%02d:%02d\n' $((s/3600)) $((s%3600/60)) $((s%60)) 
05:25:45 
$ echo 12345|awk '{printf "%02d:%02d:%02d\n",$0/3600,$0%3600/60,$0%60}' 
05:25:45 
$ gdate -d @12345 +%T 
05:25:45 
$ date -r 12345 +%T 
05:25:45 

Conversione secondi per giorni, ore, minuti e secondi:

$ t=12345678 
$ printf '%d:%02d:%02d:%02d\n' $((t/86400)) $((t/3600%24)) $((t/60%60)) $((t%60)) 
142:21:21:18 
2

Ho avuto un diverso formato dell'ora di input, quindi ecco una soluzione più flessibile. Il comando per convertire le date in BSD/MacOS è

date -jf in_format [+out_format] in_date 

dove i formati utilizzano strftime (vedi man strftime).

Per la data formato di input YYYY-MM-DD hh:mm:ss:

$ date -jf '%Y-%m-%d %H:%M:%S' '2017-05-10 13:40:01' 
Wed May 10 13:40:01 PDT 2017 

Per loro leggere in variabili distinte, mi sto prendendo l'idea di NVRAM, ma che consente di utilizzare qualsiasi formato strftime:

$ date_in='2017-05-10 13:40:01' 

$ format='%Y-%m-%d %H:%M:%S' 

$ read y m d H M S <<< "$(date -jf "$format" '+%Y %m %d %H %M %S' "$date_in")" 

$ for var in y m d H M S; do echo "$var=${!var}"; done 
y=2017 
m=05 
d=10 
H=13 
M=40 
S=01 

Nella mia caso, volevo convertire tra fusi orari (vedi la tua directory /usr/share/zoneinfo per i nomi delle zone):

$ format=%Y-%m-%dT%H:%M:%S%z 

$ TZ=UTC date -jf $format +$format 2017-05-10T02:40:01+0200 
2017-05-10T00:40:01+0000 

$ TZ=America/Los_Angeles date -jf $format +$format 2017-05-10T02:40:01+0200 
2017-05-09T17:40:01-0700