2016-06-27 7 views
1

Wenn ich jedes Mal, wenn eine Datei geschrieben wird, drei verschiedene Skripts zu verschiedenen Zeiten ausführen lassen muss, wie würde ein Bash-Skript geschrieben werden, um ein bestimmtes Skript nur zu einem bestimmten Zeitpunkt auszuführen. Dies ist nicht so einfach wie ein Cron-Job (obwohl Cron wahrscheinlich die .sh-Datei basierend auf der Zeit austauschen könnte), ich suche nach den Zeitvariablen.Zeitvariablen in der Bash-Skripterstellung

Zum Beispiel:

If 9am-11:30 am run scriptA.sh if file.txt is changed. 
If 11:30am-5:45pm run scriptB.sh if file is changed. 
If 5:46pm-8:59am run scriptC.sh if file is changed. 

fragte ich eine ähnliche Frage, aber ich glaube nicht, dass ich klar genug über die Variablen war ich suche oder wie sie definieren ..

+1

Sie könnten etwas mit "Datum" und seiner Formatierung tun, Zeitstempel in Minuten des Tages verwandeln. Z.B. '$ (Datum +"% H ") * 60 + $ (Datum +"% S ")'. (Die Multiplikation und Addition sind keine richtige Bash, eher symbolisch.) – Evert

+1

Aber ich denke, dass Ihr Cron-Job, mit einem vierten Skript, das nur ein Symlink zu dem aktuellen relevanten Skript ist, keine schlechte Idee ist. – Evert

+0

Was bedeutet "geändert"? Wurde seit wann geändert? –

Antwort

2

Das traditionelle Werkzeug zum Vergleichen von Zeitmarken, um zu bestimmen, ob der Arbeit durchgeführt werden muss oder nicht, ist make. Sein Standardverhalten besteht darin, eine Abhängigkeitskette für die angegebenen Ziele zu berechnen und festzustellen, ob sich eine der abhängigen Dateien geändert hat. Wenn nicht, muss das Ziel nicht erneut erstellt werden. Dies ist ein großartiges Werkzeug, um die Neukompilierung zu vermeiden, aber es erstreckt sich leicht auf andere Aufgaben.

Konkret würden Sie eine Flag-Datei erstellen (z. B. .made) und diese als abhängig von Ihrer file angeben. Wenn nun file geändert wurde, muss .made neu erstellt werden, und make führt die von Ihnen angegebenen Befehle aus. In diesem Szenario würden wir ein einfaches Stück Shell-Skript ausführen, dann touch .made, um die letzte (erfolgreiche) Laufzeit zu zukünftigen Läufen zu kommunizieren.

Was bleibt, ist, dass das Rezept verschiedene Befehle zu verschiedenen Zeiten ausführt. Mein Ansatz dazu wäre eine einfache case Aussage. Beachten Sie, dass make Dollarzeichen interpretiert, also müssen wir die Dollarzeichen, die an die Shell übergeben werden sollen, verdoppeln.

.made: file 
    case $$(date +%H:%M) in \ 
     09:* | 10:* | 11:[0-2]?) \ 
      scriptA.sh ;; \ 
     11:[3-5]? | 1[2-6]:* | 17:[0-3]? | 17:4[0-5]) \ 
      scriptB.sh;; \ 
     17:4[6-9] | 17:5? | 1[89]:* | 2?:* | 0[0-8]:*) \ 
      scriptC.sh;; \ 
    esac 
    touch [email protected] # [email protected] expands to the current target 

Die gesamte case Anweisung muss als eine einzige logische Linie an der Shell übergeben werden, so dass wir am Ende mit diesen lästigen Schrägstrichen bis zu den Zeilenumbrüche zu entkommen.

Beachten Sie auch, dass make wählerisch über Einrückung ist; Vor jeder (logischen) Zeile im Rezept sollte ein literales Tabulatorzeichen stehen.

Das Standardverhalten von make ist, das erste Ziel in der Datei auszuführen; Diese Makefile enthält nur ein Ziel, also make entspricht make .made.

Beachten Sie auch, dass make kümmert sich um Exit-Codes; Wenn scriptA, scriptB oder scriptC mit einem Nicht-Null-Beendigungsstatus beendet werden kann, wird dies von make als schwerwiegender Fehler betrachtet, und die Datei .made wird nicht aktualisiert. (Sie können jedoch leicht guard against this.)

+0

WOW! Ich danke dir sehr! Du hast mir eine Goldmine zum Lernen gegeben. Ich verstehe nur etwa 60% davon in diesem Moment, da ich mit der Bash die Hello World kaum hinter mir habe, aber ich hatte keine Ahnung, dass es so mächtig sein könnte. Akzeptieren Sie neue Kunden? Ich beschwere mich nicht und ich bin nicht wählerisch oder anspruchsvoll. ;) –

+1

Nicht wirklich; Ich bin voll beschäftigt. Wenn du das ernst meinst, brauchst du noch 10 Rufpunkte und dann können wir [chat] (https://chat.stackoverflow.com) – tripleee

+0

Absolut, ich bin offensichtlich über meinen Kopf hinweg. Ich habe eine Vorstellung von den Teilen des Puzzles, die benötigt werden, um das komplette Paket funktional genug zu bekommen, um glücklich zu sein, aber keine Ahnung, wie man sie bekommt. Es ist so ein Durcheinander, jetzt ist alles gehackt und der Kanal für grundlegende Funktionalität zusammengebunden ... Danke nochmal für die Hilfe und den Rat. Sprich mit dir in ein paar Tagen, wenn ich nicht zuerst wegen meiner Fragen hier rausgeschmissen werde. :) –

0

Nun, da Bash Variablen können nur string oder integer speichern, "date" Variablen sind nur ein String-Manipulationen, wie zB unter:

hours=`date +%H` 
minutes=`date +%M` 
sum=$(($hours + $minutes)) 
digit=`echo $sum | sed -e 's/\(^.*\)\(.$\)/\2/'` # counts total digits 
2

Ich sehe, es gibt zwei Probleme. 1, wie zu bestimmen, ob die aktuelle Stunde in einem bestimmten Bereich ist. 2, wie zu bestimmen, ob eine Datei kürzlich geändert wurde.

Hier ist, wie ich das würde nähern:

#!/bin/bash 

now=$(date +%s) 
current_hour=$(date +%H) 
file_mod=$(ls -l --time-style=+%s file.txt | awk '{print $(NF-1)}') 
file_age=$(($now - $file_mod)) 

if [[ $current_hour -gt 9 ]] && \ 
    [[ $current_hour -lt 11 ]] && \ 
    [[ $file_age -lt 3600 ]] 
then 
    ./scriptA.sh 
fi 

Hier verwende ich die Bash-Operatoren für numerischen Vergleich: -gt, -lt

Für eine höhere Granularität mit der Zeit würden Sie berechnen müssen die Zeit seit Mitternacht. Vielleicht so etwas wie:

hour=$(date +%H) 
min=$(date +%M) 
minutes=$(echo "(60 * $hour) + $min" | bc -l) 

eleven_thirty=$(echo "(60 * 11) + 30" | bc -l) 
+0

Ausgezeichnete Hilfe! Nehmen wir an, wir nehmen die Komplexität der Dateiänderung heraus ... Wenn ich das Skript manuell ausführe und mich nur auf den Zeitaspekt konzentriere, der sortiert werden muss. Wenn Sie größere Granularität sagen, meinen Sie damit, dass Ihr erster Codeschnipsel ein zweistündiges Fenster ist und dass 11:30 nicht berechnet wird, nur die 11. Stunde korrekt? –

+1

Ja, Sie müssten 11:30 Uhr in Minuten nach Mitternacht ausdrücken. – ddoxey

+0

Sie können "ls" durch "stat" ersetzen, aber leider sind die Details, wie Sie einen Zeitstempel daraus erhalten, auch nicht portabel. Für die Portabilität schreiben Sie vielleicht einen einfachen Perl-Ersatz. – tripleee