Data aritmetică în scripturi de shell Unix

Trebuie să fac date aritmetice în scripturile de shell Unix pe care le folosesc pentru a controla execuția programelor de la terțe părți.

Folosesc o funcție pentru a crește o zi și o altă valoare pentru a scădea:

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

dar acum trebuie să fac o aritmetică mai complexă.

Care este cel mai bun și mai compatibil mod de a face acest lucru?

0
fr hi bn

14 răspunsuri

De ce nu scrieți scripturile dvs. utilizând o limbă precum perl sau python, care acceptă în mod mai natural procesarea complexă a datelor? Sigur că o puteți face totul în bash, dar cred că veți obține și mai multă consistență între platforme folosind Python, de exemplu, atâta timp cât vă puteți asigura că perl sau python este instalat.

Trebuie să adaug că este destul de ușor să conectezi script-urile Python și Perl într-un script de shell care conține.

0
adăugat
Sunt de acord cu Justin și vă recomandăm să utilizați un instrument / o limbă mai bună pentru scriptul dvs. Probabil că aș merge cu perl, deoarece este instalat pe majoritatea sistemelor Unix din cutie. Python, în timp ce este mai modern, vă cere să instalați mai întâi acest lucru, ceea ce poate fi o durere sau chiar imposibil din punct de vedere politic.
adăugat autor markus_b, sursa
date --date='1 days ago' '+%a'

Nu este o soluție foarte compatibilă. Acesta va funcționa numai în Linux. Cel puțin, nu a funcționat în Aix și Solaris.

Lucrează în RHEL:

date --date='1 days ago' '+%Y%m%d'
20080807
0
adăugat

Presupunând că aveți data GNU , după cum urmează:

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

Și expresii similare .

0
adăugat
Pe care Unixes (Unices?) Face acest lucru?
adăugat autor Johnsyweb, sursa
Este atât de frumos să descoperiți funcționalitatea utilă care salvează ziua, într-o comandă de altă natură. Linia de comandă Unix pentru totdeauna.
adăugat autor Thalis K., sursa
Cu siguranta nu functioneaza cu data BSD, care este instalata cu OS X. Instalarea coreutils cu ceva de genul homebrew face ca versiunea GNU care adauga aceste extensii sa fie disponibila ca gdate.
adăugat autor sj26, sursa
a vrut să dea un dublu în sus! :-) a pierdut atât de mult timp pe asta! :-( multumita tie! :-)
adăugat autor Senthil Kumar, sursa
Se pare că lucrează la Linux. Nu aș fi surprins dacă ar fi o extensie GNU. Funcționează chiar și pentru compensarea sumelor arbitrare de la date arbitrare, de exemplu, "date -date = '2012-01-27 - 30 zile" "
adăugat autor Joseph Garvin, sursa

Privind mai departe, cred că poți folosi data. Am încercat următoarele pe OpenBSD: am luat data de 29 februarie 2008 și o oră aleatorie (sub formă de 080229301535) și am adăugat +1 pentru partea de zi, după cum urmează:

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

După cum puteți vedea, data formatată în timp corect ...

HTH

0
adăugat

Dacă versiunea GNU a datei funcționează pentru dvs., de ce nu apucați sursa și compilați-o pe AIX și Solaris?

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

În orice caz, sursa ar trebui să vă ajute să obțineți data corectă aritmetică dacă doriți să vă scrieți propriul cod.

Pe de altă parte, comentariile "ca soluția este bună, dar cu siguranță puteți observa că nu este la fel de bună ca și cum ar putea fi. Se pare că nimeni nu sa gândit să tinkering cu datele când a construit Unix". nu ne duceți nicăieri. Am constatat că fiecare dintre sugestiile de până acum este foarte utilă și ținta.

0
adăugat

Pentru a face aritmetică cu datele de pe UNIX obțineți data ca număr secunde de la epoca UNIX, efectuați un calcul, apoi convertiți înapoi la formatul dvs. de dată imprimabilă. Comanda pentru dată ar trebui să vă poată da atât secundele de la epocă, cât și conversia de la acel număr la o dată imprimabilă. Comanda mea locală de date face acest lucru,

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

Consultați pagina manajelor locale date (1) . Pentru a crește o zi, adăugați 86400 secunde.

0
adăugat

M-am lovit de asta de câteva ori. Gândurile mele sunt:

  1. Date arithmetic is always a pain
  2. It is a bit easier when using EPOCH date format
  3. date on Linux converts to EPOCH, but not on Solaris
  4. For a portable solution, you need to do one of the following:
    1. Install gnu date on solaris (already mentioned, needs human interaction to complete)
    2. Use perl for the date part (most unix installs include perl, so I would generally assume that this action does not require additional work).

Un exemplu de script (verifică vârsta anumitor fișiere de utilizatori pentru a vedea dacă contul poate fi șters):

#!/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);
}
0
adăugat

Dacă doriți să continuați cu awk, atunci funcțiile mktime și strftime sunt utile:


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]
     }
}
0
adăugat
dar, așa cum tocmai am descoperit, mktime este gawk, și nu acolo pe solaris awk / nawk :(
adăugat autor Joe Watkins, sursa

Cartea "Shell Script Recipes: A Problem Solution Approach" (ISBN: 978-1-59059-471-1) de către Chris F.A. Johnson are o bibliotecă de funcții de date care ar putea fi de ajutor. Codul sursă este disponibil la adresa http://apress.com/book/downloadfile/2146 ( funcțiile date sunt în capitolul08 / data-func-sh în cadrul fișierului tar).

0
adăugat

Am scris un script de bash pentru conversia datelor exprimate în engleză în convenționale mm / dd / aaaa. Se numește ComputeDate .

Iată câteva exemple de utilizare a acestuia. Pentru coincidență am plasat rezultatul fiecărei invocări pe aceeași linie ca invocarea, separată de un colon (:). Citezile de mai jos sunt nu necesare atunci când rulează 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

Am inclus acest script ca răspuns la această problemă, deoarece ilustrează modul în care pentru a face aritmetica dată printr-un set de funcții bash și aceste funcții se pot dovedi utile pentru ceilalti. Se ocupă de anii bătrâni și se înmulțesc bine secole:

#! /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 $
0
adăugat
Vedeți răspunsul meu pentru cea mai simplă soluție.
adăugat autor Harun Prasad, sursa

Iată o modalitate ușoară de a efectua calcule de date în scripting shell.

meetingDate='12/31/2011' # MM/DD/YYYY Format
reminderDate=`date --date=$meetingDate'-1 day' +'%m/%d/%Y'`
echo $reminderDate

Below are more variations of date computation that can be achieved using date utility. http://www.cyberciti.biz/tips/linux-unix-get-yesterdays-tomorrows-date.html http://www.cyberciti.biz/faq/linux-unix-formatting-dates-for-display/

Acest lucru a lucrat pentru mine pe RHEL.

0
adăugat
+1 Aceasta este ceea ce trebuia să fac aritmetică. Foarte simplu și simplu. Am corectat ordinul m / d / Y.
adăugat autor Erick Robertson, sursa

Iată cele două valori ale mele - un înveliș de script care utilizează date și grep .

Exemplu de utilizare

> 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 :-(

Script

#!/bin/sh

# Usage:
#
# datecalc ""  
#
#  ::= see "man date", section "DATE STRING"
#  ::= + | -
#  ::= INTEGER | INTEGER
#  ::= 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
0
adăugat

Pentru compatibilitatea cu BSD / OS X, puteți utiliza utilitarul de date cu -j și -v pentru a face matematica de dată. Consultați pagina de comandă FreeBSD pentru dată . Puteți combina răspunsurile anterioare ale Linux cu acest răspuns, care vă poate oferi o compatibilitate suficientă.

Pe BSD, ca Linux, care rulează date vă va da data curentă:

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

Acum, cu data BSD puteți face matematica cu -v , de exemplu, listați ziua de mâine ( + 1d este plus o zi

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

Puteți folosi o dată existentă ca bază și, opțional, specificați formatul de analiză folosind strftime și asigurați-vă că utilizați -j pentru a nu schimba data sistemului:

$ 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

Și puteți folosi acest lucru ca bază a calculelor datei:

$ 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

Rețineți că -v implică -j .

Setările multiple pot fi furnizate secvențial:

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

Consultați pagina de manevră pentru mai multe detalii.

0
adăugat
Mulțumesc pentru magie!
adăugat autor Yoga, sursa

Acest lucru funcționează pentru mine:

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'`
0
adăugat