23 Stimmen

Datumsarithmetik in Unix-Shell-Skripten

Ich muss Datumsberechnungen in Unix-Shell-Skripten durchführen, die ich zur Steuerung der Ausführung von Programmen Dritter verwende.

Ich verwende eine Funktion zum Erhöhen eines Tages und eine andere zum Verringern:

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

aber jetzt muss ich komplexere Berechnungen durchführen.

Was ist der beste und kompatibelste Weg, dies zu tun?

6voto

caerwyn Punkte 296

Wenn Sie unter UNIX mit Datumsangaben rechnen wollen, erhalten Sie das Datum als Anzahl der Sekunden seit der UNIX-Epoche, führen einige Berechnungen durch und konvertieren dann zurück in Ihr druckbares Datumsformat. Der Befehl date sollte in der Lage sein, Ihnen sowohl die Sekunden seit der Epoche zu liefern als auch diese Zahl in ein druckbares Datum umzuwandeln. Mein lokaler Datumsbefehl tut dies,

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

Siehe Ihr lokales date(1) Manpage. Um einen Tag zu erhöhen, addieren Sie 86400 Sekunden.

5voto

ggasp Punkte 1460
date --date='1 days ago' '+%a'

Das ist keine sehr kompatible Lösung. Sie wird nur unter Linux funktionieren. Zumindest funktionierte sie nicht unter Aix und Solaris.

Es funktioniert in RHEL:

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

4voto

Jonathan Bourke Punkte 215

Ich bin ein paar Mal darüber gestolpert. Meine Gedanken sind:

  1. Datumsarithmetik ist immer eine Qual
  2. Es ist etwas einfacher, wenn Sie das EPOCH-Datumsformat verwenden
  3. Datum unter Linux wird in EPOCH umgewandelt, aber nicht unter Solaris
  4. Für eine portable Lösung müssen Sie eine der folgenden Möglichkeiten nutzen:
    1. Installieren Sie gnu date auf Solaris (bereits erwähnt, erfordert menschliche Interaktion zu vervollständigen)
    2. Verwenden Sie Perl für den Datumsteil ( Die meisten Unix-Installationen umfassen perl, daher würde ich generell davon ausgehen dass diese Aktion auch no zusätzliche Arbeit erfordern).

Ein Beispielskript (prüft auf das Alter bestimmter Benutzerdateien, um festzustellen, ob das Konto gelöscht werden kann):

#!/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);
}

3voto

abyx Punkte 65176

Bei näherer Betrachtung denke ich, dass man einfach das Datum verwenden kann. Ich habe das Folgende unter OpenBSD ausprobiert: Ich habe das Datum des 29. Februar 2008 und eine zufällige Stunde (in Form von 080229301535) genommen und +1 zum Tagsteil hinzugefügt, etwa so:

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

Wie Sie sehen können, hat date die Uhrzeit korrekt formatiert...

HTH

3voto

Joe Watkins Punkte 1513

Wenn Sie mit awk weitermachen wollen, dann sind die Funktionen mktime und strftime nützlich:

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 Stimmen

Aber, wie ich gerade herausgefunden habe, ist mktime gawk, und nicht da auf solaris awk/nawk :(

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X