scripts script resueltos programas pasar parametros operaciones manejo español ejercicios ejemplos cadenas aritmeticas unix shell date math scripting

resueltos - Fecha aritmética en scripts de shell Unix



shell script ejemplos (14)

¿Por qué no escribir sus scripts usando un lenguaje como perl o python en su lugar, que de forma más natural es compatible con el complejo procesamiento de fechas? Claro que puedes hacerlo todo en bash, pero creo que también obtendrás más consistencia en todas las plataformas que usan Python, por ejemplo, siempre y cuando puedas asegurarte de que Perl o Python estén instalados.

Debo añadir que es bastante fácil de conectar en scripts de Python y Perl en un script de shell que contiene.

Necesito hacer aritmética de fecha en las secuencias de comandos de shell de Unix que utilizo para controlar la ejecución de programas de terceros.

Estoy usando una función para incrementar un día y otra para disminuir:

IncrementaDia(){ echo $1 | awk '' BEGIN { diasDelMes[1] = 31 diasDelMes[2] = 28 diasDelMes[3] = 31 diasDelMes[4] = 30 diasDelMes[5] = 31 diasDelMes[6] = 30 diasDelMes[7] = 31 diasDelMes[8] = 31 diasDelMes[9] = 30 diasDelMes[10] = 31 diasDelMes[11] = 30 diasDelMes[12] = 31 } { anio=substr($1,1,4) mes=substr($1,5,2) dia=substr($1,7,2) if((anio % 4 == 0 && anio % 100 != 0) || anio % 400 == 0) { diasDelMes[2] = 29; } if( dia == diasDelMes[int(mes)] ) { if( int(mes) == 12 ) { anio = anio + 1 mes = 1 dia = 1 } else { mes = mes + 1 dia = 1 } } else { dia = dia + 1 } } END { printf("%04d%02d%02d", anio, mes, dia) } '' } if [ $# -eq 1 ]; then tomorrow=$1 else today=$(date +"%Y%m%d") tomorrow=$(IncrementaDia $hoy) fi

pero ahora necesito hacer una aritmética más compleja.

¿Cuál es la mejor y más compatible manera de hacer esto?


Al analizarlo más a fondo, creo que simplemente puede usar la fecha. He intentado lo siguiente en OpenBSD: tomé la fecha del 29 de febrero de 2008 y una hora aleatoria (en el formato de 080229301535) y agregué +1 a la parte del día, de esta manera:

$ date -j 0802301535 Sat Mar 1 15:35:00 EST 2008

Como puede ver, la fecha se formateó correctamente ...

HTH


Si la versión de la fecha GNU le funciona, ¿por qué no toma la fuente y la compila en AIX y Solaris?

http://www.gnu.org/software/coreutils/

En cualquier caso, la fuente debe ayudarlo a obtener la aritmética de la fecha correcta si va a escribir su propio código.

Por otro lado, comentarios como "esa solución es buena pero seguramente se nota que no es tan buena como puede ser. Parece que a nadie se le ocurrió jugar con las fechas cuando se construyó Unix". no nos lleves a ningún lado. Encontré que cada una de las sugerencias hasta ahora es muy útil y objetivo.


El libro "Recetas de Shell Script: un enfoque de solución de problemas" (ISBN: 978-1-59059-471-1) de Chris FA Johnson tiene una biblioteca de funciones de fecha que podría ser útil. El código fuente está disponible en http://apress.com/book/downloadfile/2146 (las funciones de fecha están en Chapter08 / data-funcs-sh dentro del archivo tar).


Me he topado con esto un par de veces. Mis pensamientos son:

  1. La aritmética de la fecha es siempre un dolor
  2. Es un poco más fácil cuando se utiliza el formato de fecha EPOCH
  3. la fecha en Linux se convierte en EPOCH, pero no en Solaris
  4. Para una solución portátil, debe hacer una de las siguientes cosas:
    1. Instalar gnu date en solaris (ya mencionado, necesita interacción humana para completar)
    2. Use perl para la parte de fecha (la mayoría de las instalaciones de Unix incluyen perl, por lo que generalmente asumiría que esta acción no requiere trabajo adicional).

Un script de muestra (verifica la antigüedad de ciertos archivos de usuario para ver si la cuenta se puede eliminar):

#!/usr/local/bin/perl $today = time(); $user = $ARGV[0]; $command="awk -F: ''/$user/ {print /$6}'' /etc/passwd"; chomp ($user_dir = `$command`); if ( -f "$user_dir/.sh_history" ) { @file_dates = stat("$user_dir/.sh_history"); $sh_file_date = $file_dates[8]; } else { $sh_file_date = 0; } if ( -f "$user_dir/.bash_history" ) { @file_dates = stat("$user_dir/.bash_history"); $bash_file_date = $file_dates[8]; } else { $bash_file_date = 0; } if ( $sh_file_date > $bash_file_date ) { $file_date = $sh_file_date; } else { $file_date = $bash_file_date; } $difference = $today - $file_date; if ( $difference >= 3888000 ) { print "User needs to be disabled, 45 days old or older!/n"; exit (1); } else { print "OK/n"; exit (0); }


Si desea continuar con awk, entonces las funciones mktime y strftime son útiles:

BEGIN { dateinit } { newdate=daysadd(OldDate,DaysToAdd)} # daynum: convert DD-MON-YYYY to day count #----------------------------------------- function daynum(date, d,m,y,i,n) { y=substr(date,8,4) m=gmonths[toupper(substr(date,4,3))] d=substr(date,1,2) return mktime(y" "m" "d" 12 00 00") } #numday: convert day count to DD-MON-YYYY #------------------------------------------- function numday(n, y,m,d) { m=toupper(substr(strftime("%B",n),1,3)) return strftime("%d-"m"-%Y",n) } # daysadd: add (or subtract) days from date (DD-MON-YYYY), return new date (DD-MON-YYYY) #------------------------------------------ function daysadd(date, days) { return numday(daynum(date)+(days*86400)) } #init variables for date calcs #----------------------------------------- function dateinit( x,y,z) { # Stuff for date calcs split("JAN:1,FEB:2,MAR:3,APR:4,MAY:5,JUN:6,JUL:7,AUG:8,SEP:9,OCT:10,NOV:11,DEC:12", z) for (x in z) { split(z[x],y,":") gmonths[y[1]]=y[2] } }


Para hacer operaciones aritméticas con fechas en UNIX, obtienes la fecha como el número de segundos desde la época UNIX, haz algunos cálculos y luego vuelve a convertir a tu formato de fecha imprimible. El comando de fecha debería poder darle los segundos desde la época y convertir desde ese número a una fecha imprimible. Mi comando de fecha local hace esto,

% date -n 1219371462 % date 1219371462 Thu Aug 21 22:17:42 EDT 2008 %

Consulte su página de manual de date(1) local date(1) . Para incrementar un día, agregue 86400 segundos.


He escrito un script bash para convertir fechas expresadas en inglés en fechas mm / dd / aaaa convencionales. Se llama ComputeDate .

Aquí hay algunos ejemplos de su uso. Para abreviar, he colocado la salida de cada invocación en la misma línea que la invocación, separada por dos puntos (:). Las comillas que se muestran a continuación no son necesarias cuando se ejecuta ComputeDate :

$ ComputeDate ''yesterday'': 03/19/2010 $ ComputeDate ''yes'': 03/19/2010 $ ComputeDate ''today'': 03/20/2010 $ ComputeDate ''tod'': 03/20/2010 $ ComputeDate ''now'': 03/20/2010 $ ComputeDate ''tomorrow'': 03/21/2010 $ ComputeDate ''tom'': 03/21/2010 $ ComputeDate ''10/29/32'': 10/29/2032 $ ComputeDate ''October 29'': 10/1/2029 $ ComputeDate ''October 29, 2010'': 10/29/2010 $ ComputeDate ''this monday'': ''this monday'' has passed. Did you mean ''next monday?'' $ ComputeDate ''a week after today'': 03/27/2010 $ ComputeDate ''this satu'': 03/20/2010 $ ComputeDate ''next monday'': 03/22/2010 $ ComputeDate ''next thur'': 03/25/2010 $ ComputeDate ''mon in 2 weeks'': 03/28/2010 $ ComputeDate ''the last day of the month'': 03/31/2010 $ ComputeDate ''the last day of feb'': 2/28/2010 $ ComputeDate ''the last day of feb 2000'': 2/29/2000 $ ComputeDate ''1 week from yesterday'': 03/26/2010 $ ComputeDate ''1 week from today'': 03/27/2010 $ ComputeDate ''1 week from tomorrow'': 03/28/2010 $ ComputeDate ''2 weeks from yesterday'': 4/2/2010 $ ComputeDate ''2 weeks from today'': 4/3/2010 $ ComputeDate ''2 weeks from tomorrow'': 4/4/2010 $ ComputeDate ''1 week after the last day of march'': 4/7/2010 $ ComputeDate ''1 week after next Thursday'': 4/1/2010 $ ComputeDate ''2 weeks after the last day of march'': 4/14/2010 $ ComputeDate ''2 weeks after 1 day after the last day of march'': 4/15/2010 $ ComputeDate ''1 day after the last day of march'': 4/1/2010 $ ComputeDate ''1 day after 1 day after 1 day after 1 day after today'': 03/24/2010

He incluido esta secuencia de comandos como una respuesta a este problema porque ilustra cómo hacer la aritmética de la fecha a través de un conjunto de funciones de bash y estas funciones pueden ser útiles para otras. Maneja los años bisiestos y salta siglos correctamente:

#! /bin/bash # ConvertDate -- convert a human-readable date to a MM/DD/YY date # # Date ::= Month/Day/Year # | Month/Day # | DayOfWeek # | [this|next] DayOfWeek # | DayofWeek [of|in] [Number|next] weeks[s] # | Number [day|week][s] from Date # | the last day of the month # | the last day of Month # # Month ::= January | February | March | April | May | ... | December # January ::= jan | january | 1 # February ::= feb | january | 2 # ... # December ::= dec | december | 12 # Day ::= 1 | 2 | ... | 31 # DayOfWeek ::= today | Sunday | Monday | Tuesday | ... | Saturday # Sunday ::= sun* # ... # Saturday ::= sat* # # Number ::= Day | a # # Author: Larry Morell if [ $# = 0 ]; then printdirections $0 exit fi # Request the value of a variable GetVar () { Var=$1 echo -n "$Var= [${!Var}]: " local X read X if [ ! -z $X ]; then eval $Var="$X" fi } IsLeapYear () { local Year=$1 if [ $[20$Year % 4] -eq 0 ]; then echo yes else echo no fi } # AddToDate -- compute another date within the same year DayNames=(mon tue wed thu fri sat sun ) # To correspond with ''date'' output Day2Int () { ErrorFlag= case $1 in -e ) ErrorFlag=-e; shift ;; esac local dow=$1 n=0 while [ $n -lt 7 -a $dow != "${DayNames[n]}" ]; do let n++ done if [ -z "$ErrorFlag" -a $n -eq 7 ]; then echo Cannot convert $dow to a numeric day of wee exit fi echo $[n+1] } Months=(31 28 31 30 31 30 31 31 30 31 30 31) MonthNames=(jan feb mar apr may jun jul aug sep oct nov dec) # Returns the month (1-12) from a date, or a month name Month2Int () { ErrorFlag= case $1 in -e ) ErrorFlag=-e; shift ;; esac M=$1 Month=${M%%/*} # Remove /... case $Month in [a-z]* ) Month=${Month:0:3} M=0 while [ $M -lt 12 -a ${MonthNames[M]} != $Month ]; do let M++ done let M++ esac if [ -z "$ErrorFlag" -a $M -gt 12 ]; then echo "''$Month'' Is not a valid month." exit fi echo $M } # Retrieve month,day,year from a legal date GetMonth() { echo ${1%%/*} } GetDay() { echo $1 | col / 2 } GetYear() { echo ${1##*/} } AddToDate() { local Date=$1 local days=$2 local Month=`GetMonth $Date` local Day=`echo $Date | col / 2` # Day of Date local Year=`echo $Date | col / 3` # Year of Date local LeapYear=`IsLeapYear $Year` if [ $LeapYear = "yes" ]; then let Months[1]++ fi Day=$[Day+days] while [ $Day -gt ${Months[$Month-1]} ]; do Day=$[Day - ${Months[$Month-1]}] let Month++ done echo "$Month/$Day/$Year" } # Convert a date to normal form NormalizeDate () { Date=`echo "$*" | sed ''sX *X/Xg''` local Day=`date +%d` local Month=`date +%m` local Year=`date +%Y` #echo Normalizing Date=$Date > /dev/tty case $Date in */*/* ) Month=`echo $Date | col / 1 ` Month=`Month2Int $Month` Day=`echo $Date | col / 2` Year=`echo $Date | col / 3` ;; */* ) Month=`echo $Date | col / 1 ` Month=`Month2Int $Month` Day=1 Year=`echo $Date | col / 2 ` ;; [a-z]* ) # Better be a month or day of week Exp=${Date:0:3} case $Exp in jan|feb|mar|apr|may|june|jul|aug|sep|oct|nov|dec ) Month=$Exp Month=`Month2Int $Month` Day=1 #Year stays the same ;; mon|tue|wed|thu|fri|sat|sun ) # Compute the next such day local DayOfWeek=`date +%u` D=`Day2Int $Exp` if [ $DayOfWeek -le $D ]; then Date=`AddToDate $Month/$Day/$Year $[D-DayOfWeek]` else Date=`AddToDate $Month/$Day/$Year $[7+D-DayOfWeek]` fi # Reset Month/Day/Year Month=`echo $Date | col / 1 ` Day=`echo $Date | col / 2` Year=`echo $Date | col / 3` ;; * ) echo "$Exp is not a valid month or day" exit ;; esac ;; * ) echo "$Date is not a valid date" exit ;; esac case $Day in [0-9]* );; # Day must be numeric * ) echo "$Date is not a valid date" exit ;; esac [0-9][0-9][0-9][0-9] );; # Year must be 4 digits [0-9][0-9] ) Year=20$Year ;; esac Date=$Month/$Day/$Year echo $Date } # NormalizeDate jan # NormalizeDate january # NormalizeDate jan 2009 # NormalizeDate jan 22 1983 # NormalizeDate 1/22 # NormalizeDate 1 22 # NormalizeDate sat # NormalizeDate sun # NormalizeDate mon ComputeExtension () { local Date=$1; shift local Month=`GetMonth $Date` local Day=`echo $Date | col / 2` local Year=`echo $Date | col / 3` local ExtensionExp="$*" case $ExtensionExp in *w*d* ) # like 5 weeks 3 days or even 5w2d ExtensionExp=`echo $ExtensionExp | sed ''s/[a-z]/ /g''` weeks=`echo $ExtensionExp | col 1` days=`echo $ExtensionExp | col 2` days=$[7*weeks+days] Due=`AddToDate $Month/$Day/$Year $days` ;; *d ) # Like 5 days or 5d ExtensionExp=`echo $ExtensionExp | sed ''s/[a-z]/ /g''` days=$ExtensionExp Due=`AddToDate $Month/$Day/$Year $days` ;; * ) Due=$ExtensionExp ;; esac echo $Due } # Pop -- remove the first element from an array and shift left Pop () { Var=$1 eval "unset $Var[0]" eval "$Var=(/${$Var[*]})" } ComputeDate () { local Date=`NormalizeDate $1`; shift local Expression=`echo $* | sed ''s/^ *a /1 /;s/,/ /'' | tr A-Z a-z ` local Exp=(`echo $Expression `) local Token=$Exp # first one local Ans= #echo "Computing date for ${Exp[*]}" > /dev/tty case $Token in */* ) # Regular date M=`GetMonth $Token` D=`GetDay $Token` Y=`GetYear $Token` if [ -z "$Y" ]; then Y=$Year elif [ ${#Y} -eq 2 ]; then Y=20$Y fi Ans="$M/$D/$Y" ;; yes* ) Ans=`AddToDate $Date -1` ;; tod*|now ) Ans=$Date ;; tom* ) Ans=`AddToDate $Date 1` ;; the ) case $Expression in *day*after* ) #the day after Date Pop Exp; # Skip the Pop Exp; # Skip day Pop Exp; # Skip after #echo Calling ComputeDate $Date ${Exp[*]} > /dev/tty Date=`ComputeDate $Date ${Exp[*]}` #Recursive call #echo "New date is " $Date > /dev/tty Ans=`AddToDate $Date 1` ;; *last*day*of*th*month|*end*of*th*month ) M=`date +%m` Day=${Months[M-1]} if [ $M -eq 2 -a `IsLeapYear $Year` = yes ]; then let Day++ fi Ans=$Month/$Day/$Year ;; *last*day*of* ) D=${Expression##*of } D=`NormalizeDate $D` M=`GetMonth $D` Y=`GetYear $D` # echo M is $M > /dev/tty Day=${Months[M-1]} if [ $M -eq 2 -a `IsLeapYear $Y` = yes ]; then let Day++ fi Ans=$[M]/$Day/$Y ;; * ) echo "Unknown expression: " $Expression exit ;; esac ;; next* ) # next DayOfWeek Pop Exp dow=`Day2Int $DayOfWeek` # First 3 chars tdow=`Day2Int ${Exp:0:3}` # First 3 chars n=$[7-dow+tdow] Ans=`AddToDate $Date $n` ;; this* ) Pop Exp dow=`Day2Int $DayOfWeek` tdow=`Day2Int ${Exp:0:3}` # First 3 chars if [ $dow -gt $tdow ]; then echo "''this $Exp'' has passed. Did you mean ''next $Exp?''" exit fi n=$[tdow-dow] Ans=`AddToDate $Date $n` ;; [a-z]* ) # DayOfWeek ... M=${Exp:0:3} case $M in jan|feb|mar|apr|may|june|jul|aug|sep|oct|nov|dec ) ND=`NormalizeDate ${Exp[*]}` Ans=$ND ;; mon|tue|wed|thu|fri|sat|sun ) dow=`Day2Int $DayOfWeek` Ans=`NormalizeDate $Exp` if [ ${#Exp[*]} -gt 1 ]; then # Just a DayOfWeek #tdow=`GetDay $Exp` # First 3 chars #if [ $dow -gt $tdow ]; then #echo "''this $Exp'' has passed. Did you mean ''next $Exp''?" #exit #fi #n=$[tdow-dow] #else # DayOfWeek in a future week Pop Exp # toss monday Pop Exp # toss in/off if [ $Exp = next ]; then Exp=2 fi n=$[7*(Exp-1)] # number of weeks n=$[n+7-dow+tdow] Ans=`AddToDate $Date $n` fi ;; esac ;; [0-9]* ) # Number weeks [from|after] Date n=$Exp Pop Exp; case $Exp in w* ) let n=7*n;; esac Pop Exp; Pop Exp #echo Calling ComputeDate $Date ${Exp[*]} > /dev/tty Date=`ComputeDate $Date ${Exp[*]}` #Recursive call #echo "New date is " $Date > /dev/tty Ans=`AddToDate $Date $n` ;; esac echo $Ans } Year=`date +%Y` Month=`date +%m` Day=`date +%d` DayOfWeek=`date +%a |tr A-Z a-z` Date="$Month/$Day/$Year" ComputeDate $Date $*

Este script hace un uso extensivo de otro script que escribí (llamado col ... muchas disculpas para aquellos que usan el col estándar suministrado con Linux). Esta versión de col simplifica la extracción de columnas del stdin. Así,

$ echo a b c d e | col 5 3 2

huellas dactilares

e c b

Aquí está el script col :

#!/bin/sh # col -- extract columns from a file # Usage: # col [-r] [c] col-1 col-2 ... # where [c] if supplied defines the field separator # where each col-i represents a column interpreted according to the presence of -r as follows: # -r present : counting starts from the right end of the line # -r absent : counting starts from the left side of the line Separator=" " Reverse=false case "$1" in -r ) Reverse=true; shift; ;; [0-9]* ) ;; * )Separator="$1"; shift; ;; esac case "$1" in -r ) Reverse=true; shift; ;; [0-9]* ) ;; * )Separator="$1"; shift; ;; esac # Replace each col-i with $i Cols="" for f in $* do if [ $Reverse = true ]; then Cols="$Cols /$(NF-$f+1)," else Cols="$Cols /$$f," fi done Cols=`echo "$Cols" | sed ''s/,$//''` #echo "Using column specifications of $Cols" awk -F "$Separator" "{print $Cols}"

También utiliza printdirections para imprimir indicaciones cuando el script se invoca incorrectamente:

#!/bin/sh # # printdirections -- print header lines of a shell script # # Usage: # printdirections path # where # path is a *full* path to the shell script in question # beginning with ''/'' # # To use printdirections, you must include (as comments at the top # of your shell script) documentation for running the shell script. if [ $# -eq 0 -o "$*" = "-h" ]; then printdirections $0 exit fi # Delete the command invocation at the top of the file, if any # Delete from the place where printdirections occurs to the end of the file # Remove the # comments # There is a bizarre oddity here. sed ''/#!/d;/.*printdirections/,$d;/ *#/!d;s/# //;s/#//'' $1 > /tmp/printdirections.$$ # Count the number of lines numlines=`wc -l /tmp/printdirections.$$ | awk ''{print $1}''` # Remove the last line numlines=`expr $numlines - 1` head -n $numlines /tmp/printdirections.$$ rm /tmp/printdirections.$$

Para utilizarlo, coloque las tres secuencias de comandos en los archivos ComputeDate , col e printdirections , respectivamente. Coloque el archivo en el directorio nombrado por su RUTA, generalmente, ~ / bin. Entonces hazlos ejecutables con:

$ chmod a+x ComputeDate col printdirections

¿Problemas? Envíeme un correo electrónico: morell AT cs.atu.edu Coloque ComputeDate en el asunto.


Estos son mis dos centavos que vale la pena: un envoltorio de script que utiliza date y grep .

Ejemplo de uso

> sh ./datecalc.sh "2012-08-04 19:43:00" + 1s 2012-08-04 19:43:00 + 0d0h0m1s 2012-08-04 19:43:01 > sh ./datecalc.sh "2012-08-04 19:43:00" - 1s1m1h1d 2012-08-04 19:43:00 - 1d1h1m1s 2012-08-03 18:41:59 > sh ./datecalc.sh "2012-08-04 19:43:00" - 1d2d1h2h1m2m1s2sblahblah 2012-08-04 19:43:00 - 1d1h1m1s 2012-08-03 18:41:59 > sh ./datecalc.sh "2012-08-04 19:43:00" x 1d Bad operator :-( > sh ./datecalc.sh "2012-08-04 19:43:00" Missing arguments :-( > sh ./datecalc.sh gibberish + 1h date: invalid date `gibberish'' Invalid date :-(

Guión

#!/bin/sh # Usage: # # datecalc "<date>" <operator> <period> # # <date> ::= see "man date", section "DATE STRING" # <operator> ::= + | - # <period> ::= INTEGER<unit> | INTEGER<unit><period> # <unit> ::= s | m | h | d if [ $# -lt 3 ]; then echo "Missing arguments :-(" exit; fi date=`eval "date -d /"$1/" +%s"` if [ -z $date ]; then echo "Invalid date :-(" exit; fi if ! ([ $2 == "-" ] || [ $2 == "+" ]); then echo "Bad operator :-(" exit; fi op=$2 minute=$[60] hour=$[$minute*$minute] day=$[24*$hour] s=`echo $3 | grep -oe ''[0-9]*s'' | grep -m 1 -oe ''[0-9]*''` m=`echo $3 | grep -oe ''[0-9]*m'' | grep -m 1 -oe ''[0-9]*''` h=`echo $3 | grep -oe ''[0-9]*h'' | grep -m 1 -oe ''[0-9]*''` d=`echo $3 | grep -oe ''[0-9]*d'' | grep -m 1 -oe ''[0-9]*''` if [ -z $s ]; then s=0; fi if [ -z $m ]; then m=0; fi if [ -z $h ]; then h=0; fi if [ -z $d ]; then d=0; fi ms=$[$m*$minute] hs=$[$h*$hour] ds=$[$d*$day] sum=$[$s+$ms+$hs+$ds] out=$[$date$op$sum] formattedout=`eval "date -d @$out +/"%Y-%m-%d %H:%M:%S/""` echo $1 $2 $d"d"$h"h"$m"m"$s"s" echo $formattedout



date --date=''1 days ago'' ''+%a''

No es una solución muy compatible. Funcionará solo en Linux. Al menos, no funcionó en Aix y Solaris.

Funciona en RHEL:

date --date=''1 days ago'' ''+%Y%m%d'' 20080807


Para la compatibilidad BSD / OS X, también puede usar la utilidad de fecha con -j y -v para hacer la fecha matemática. Consulte la página de manual de FreeBSD para conocer la fecha . Podría combinar las respuestas de Linux anteriores con esta respuesta que podría proporcionarle compatibilidad suficiente.

En BSD, como Linux, la date ejecución le dará la fecha actual:

$ date Wed 12 Nov 2014 13:36:00 AEDT

Ahora con la fecha de BSD puedes hacer matemática con -v , por ejemplo, enumerar la fecha de mañana ( +1d es más un día ):

$ date -v +1d Thu 13 Nov 2014 13:36:34 AEDT

Puede utilizar una fecha existente como base y, opcionalmente, especificar el formato de análisis utilizando strftime, y asegurarse de usar -j para no cambiar la fecha del sistema:

$ date -j -f "%a %b %d %H:%M:%S %Y %z" "Sat Aug 09 13:37:14 2014 +1100" Sat 9 Aug 2014 12:37:14 AEST

Y puede usar esto como la base de los cálculos de fecha:

$ date -v +1d -f "%a %b %d %H:%M:%S %Y %z" "Sat Aug 09 13:37:14 2014 +1100" Sun 10 Aug 2014 12:37:14 AEST

Tenga en cuenta que -v implica -j .

Se pueden proporcionar múltiples ajustes secuencialmente:

$ date -v +1m -v -1w Fri 5 Dec 2014 13:40:07 AEDT

Vea la página de manual para más detalles.



Esto funciona para mí:

TZ=GMT+6; export TZ mes=`date --date=''2 days ago'' ''+%m''` dia=`date --date=''2 days ago'' ''+%d''` anio=`date --date=''2 days ago'' ''+%Y''` hora=`date --date=''2 days ago'' ''+%H''`