Comment analyseriez-vous une date dans bash, avec des champs séparés (années, mois, jours, heures, minutes, secondes) dans différentes variables?
Le format de date est: YYYY-MM-DD hh:mm:ss
Est-ce que ça doit être bash? Vous pouvez utiliser le binaire GNU coreutils /bin/date
pour de nombreuses transformations:
$ 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
Ceci analyse la date donnée et l'affiche dans le format choisi. Vous pouvez adapter cela à votre guise.
C’est simple: convertissez simplement vos tirets et vos deux points en un espace (inutile de changer d’IFS) et utilisez le mot 'read' sur une seule ligne:
read Y M D h m s <<< ${date//[-:]/ }
Par exemple:
$ 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
J'avais un format d'heure d'entrée différent, alors voici une solution plus flexible.
date -jf in_format [+out_format] in_date
où les formats utilisent strftime (voir man strftime
).
Pour le format d'entrée donné 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
Pour les lire dans des variables séparées, je reprends l'idée de NVRAM, mais vous permet d'utiliser n'importe quel format strftime:
$ date_in='2017-05-10 13:40:01'
$ format='%Y-%m-%d %H:%M:%S'
$ read -r 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
(Dans les scripts, toujours utilisez read -r
.)
Dans mon cas, je voulais convertir entre les fuseaux horaires (voir votre répertoire /usr/share/zoneinfo
pour les noms de 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
Sur un Mac, vous pouvez installer la version GNU de
date
en tant quegdate
avecbrew install coreutils
.
date [+out_format] -d in_date
où out_format utilise strftime (voir man strftime
).
Dans la commande date
de GNU de coreutils, il n’existe aucun moyen de définir explicitement un format d’entrée, car il essaie de déterminer le format d’entrée lui-même, et tout fonctionne normalement. (Pour plus de détails, vous pouvez lire le manuel sur coreutils: formats de saisie de date .)
Par exemple:
$ date '+%Y %m %d %H %M %S' -d '2017-05-10 13:40:01'
2017 05 10 13 40 01
Pour les lire dans des variables distinctes, modifiez la commande dans la section Mac en remplaçant la commande dans la parenthèse par la version GNU.
Pour convertir des fuseaux horaires (voir votre répertoire /usr/share/zoneinfo
pour les noms de zone), vous pouvez spécifier TZ="America/Los_Angeles"
dans votre chaîne de saisie. Notez les caractères "
littéraux autour du nom de la zone et le caractère espace avant in_date:
TZ=out_tz date [+out_format] 'TZ="in_tz" 'in_date
Par exemple:
$ format='%Y-%m-%d %H:%M:%S%z'
$ TZ=America/Los_Angeles date +"$format" -d 'TZ="UTC" 2017-05-10 02:40:01'
2017-05-09 19:40:01-0700
$ TZ=UTC date +"$format" -d 'TZ="America/Los_Angeles" 2017-05-09 19:40:01'
2017-05-10 02:40:01+0000
La date GNU comprend également les décalages horaires pour le fuseau horaire:
$ TZ=UTC date +"$format" -d '2017-05-09 19:40:01-0700'
2017-05-10 02:40:01+0000
$ 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
La méthode array est peut-être mieux, mais voici ce que vous demandiez spécifiquement:
IFS=" :-"
read year month day hour minute second < <(echo "YYYY-MM-DD hh:mm:ss")
au lieu d'utiliser les scripts Shell, incorporez-les comme vous le souhaitez, comme ci-dessous, lorsque vous avez besoin
a=date +%Y
b=date +%S
c=date +%H
a sera l'année b sera la seconde c sera l'heure. etc.
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
Une autre solution au problème du PO:
IFS=' -:' read y m d h m s<<<'2014-03-26 16:36:41'
Conversion d'une date dans un autre format avec BSD date
et 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
reconnaît Wed
et Mar
même dans des paramètres régionaux autres que l'anglais, mais BSD date
ne le reconnaît pas.
Conversion de secondes depuis Epoch en date et heure avec la date GNU et la date BSD:
$ gdate -d @1234567890 '+%F %T'
2009-02-14 01:31:30
$ date -r 1234567890 '+%F %T'
2009-02-14 01:31:30
Conversion de secondes en heures, minutes et secondes avec un shell POSIX, POSIX awk
, GNU date
et 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
Conversion de secondes en jours, heures, minutes et secondes:
$ t=12345678
$ printf '%d:%02d:%02d:%02d\n' $((t/86400)) $((t/3600%24)) $((t/60%60)) $((t%60))
142:21:21:18
une autre pure bash
$ d="2009-12-03 15:35:11"
$ d=${d//[- :]/|}
$ IFS="|"
$ set -- $d
$ echo $1
2009
$ echo $2
12
$ echo $@
2009 12 03 15 35 11
avez-vous essayé d'utiliser cut? quelque chose comme ceci: dayofweek = date|cut -d" " -f1