ubuntuusers.de

bash - script aus einer laufenden Schleife aufrufen

Status: Ungelöst | Ubuntu-Version: Ubuntu 22.04 (Jammy Jellyfish)
Antworten |

banause

Anmeldungsdatum:
17. November 2009

Beiträge: 301

Hallo Foristen,

ich habe ein bash-script, das in einer while true-Schleife zeitkritisch (xx:00 Uhr, xx:15 Uhr, xx:30 Uhr, xx:45 Uhr, xx+1:00 Uhr usw.) alle 15 Minuten eine Datei erzeugt. Soweit alles prima. Diese erzeugten Dateien sollen von einem zweiten script möglichst direkt nach deren Entstehung weiter bearbeitet werden, ohne dass nennenswert Zeit für das aufrufende script vergeht.

Ich hatte so etwas schon einmal mit inotifywait gemacht, was aber leider nicht sehr zuverlässig war, weswegen ich die watches jede Nacht über einen cron-job neu gesetzt habe. Außerdem erscheint mir das für den vorliegenden Fall zu umständlich.

Ich hätte gerne so etwas:

script1:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
while true
    do
        mache für 14 Minuten und 58 Sekunden etwas und erzeuge davon eine Datei
        
        # Aufruf des zweiten scripts, OHNE dass dieses script1
        # auf Beendigung des aufgerufenen scripts wartet

        Aufruf script2

        # um einen Abbruch mit CTRL-C zu ermöglichen
        sleep 2
done

Parameter aus dem ersten script an das zweite script übergeben zu können wäre schick, müsste aber nicht unbedingt sein.

Wie muss der "Aufruf script2" aussehen, so dass das erste script direkt weitermacht, ohne auf die Beendigung von script2 zu warten?

Vielen Dank für hilfreiche Tipps.

Gruß,

banause

frostschutz

Avatar von frostschutz

Anmeldungsdatum:
18. November 2010

Beiträge: 7790

Im einfachsten Fall, ein & hinter den Befehl, um diesen in den Hintergrund zu schicken.

Dann ggf. am Scriptende (nach done) noch ein wait um auf die Hintergrund-Sachen zu warten.

Wenn die Zeit nirgends mit date o.ä. abgeglichen wird dann wird sich das trotzdem kontinuierlich ein wenig verzögern.

banause

(Themenstarter)

Anmeldungsdatum:
17. November 2009

Beiträge: 301

frostschutz schrieb:

Im einfachsten Fall, ein & hinter den Befehl, um diesen in den Hintergrund zu schicken.

Meinst Du so?:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
while true
    do
        mache für 14 Minuten und 58 Sekunden etwas und erzeuge davon eine Datei
        
        # Aufruf des zweiten scripts, OHNE dass dieses script1
        # auf Beendigung des aufgerufenen scripts wartet

        ./script2 &

        # um einen Abbruch mit CTRL-C zu ermöglichen
        sleep 2
done

Das werde ich mal probieren, danke.

frostschutz schrieb:

Dann ggf. am Scriptende (nach done) noch ein wait um auf die Hintergrund-Sachen zu warten.

Das habe ich nicht verstanden. Nach dem Aufruf ./script2 & würde script2 im Hintergrund ganz unabhängig laufen bis es fertig ist - so hätte ich zumindest gehofft. Der reguläre Ablauf von script1 erreicht ein wait nach dem done nicht. Wenn ich die Schleife mit einem CTRL-C unterbreche, dann kann das an einer Stelle sein, an der script 2 schon aufgerufen war oder nicht. Im ersten Fall sollte es doch einfach so zu Ende laufen.

frostschutz schrieb:

Wenn die Zeit nirgends mit date o.ä. abgeglichen wird dann wird sich das trotzdem kontinuierlich ein wenig verzögern.

stimmt, daher mache ich das so:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
recalStartTime()
{

# die fuehrenden Nullen bei einstelligen Zahlen abschneiden
MIN=`date +%M`
MIN=${MIN#"0"}
SEK=`date +%S`
SEK=${SEK#"0"}

if [ $MIN -ge 0 -a $MIN -lt 15 ] 
	then
		L=$(( $(( 14 - $MIN )) * 60 + $(( 60 - $SEK )) ))
elif [ $MIN -ge 15 -a $MIN -lt 30 ] 
	then
		L=$(( $(( 29 - $MIN )) * 60 + $(( 60 - $SEK )) ))
elif [ $MIN -ge 30 -a $MIN -lt 45 ] 
	then
		L=$(( $(( 44 - $MIN )) * 60 + $(( 60 - $SEK )) ))
elif [ $MIN -ge 45 -a $MIN -lt 60 ] 
	then
		L=$(( $(( 59 - $MIN )) * 60 + $(( 60 - $SEK )) ))
fi

# Verzoegerung in Sekunden für den Programmabschluss und den anschliessenden Neustart vorsehen
VERZ=2
L=$(( $L - $VERZ ))
L=$L"s"

echo "recalStartTime: L="$L
echo "# recalStartTime: L="$L >> $LogFILE	

}

Leider habe ich die IFs nicht mit einem case vermeiden können. Ich habe es nicht geschafft, die Tests zusammen mit case zum Laufen zu bekommen.

Gruß,

banause

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13216

banause schrieb:

frostschutz schrieb:

Dann ggf. am Scriptende (nach done) noch ein wait um auf die Hintergrund-Sachen zu warten.

Das habe ich nicht verstanden. Nach dem Aufruf ./script2 & würde script2 im Hintergrund ganz unabhängig laufen bis es fertig ist - so hätte ich zumindest gehofft. Der reguläre Ablauf von script1 erreicht ein wait nach dem done nicht. Wenn ich die Schleife mit einem CTRL-C unterbreche, dann kann das an einer Stelle sein, an der script 2 schon aufgerufen war oder nicht. Im ersten Fall sollte es doch einfach so zu Ende laufen.

Ja, in dem Falle des ewig laufenden Skriptes ist wait nicht sinnvoll. Aber dieses ewig laufende Skript, das alle Viertelstunde etwas tut, klingt falsch. So etwas würde man eher mit einem Systemd-Timer erledigen. Mir ist auch nicht klar, warum es zwei Skripte geben muss: das erste Skript kann doch die Arbeit machen, die Datei zu erzeugen, und die weitere Verarbeitung. Man müsste dann nur darauf achten, dass der Timer auch feuert, wenn die letzte Verarbeitung noch unterwegs ist.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17622

Wohnort: Berlin

Schnipseliges:

banause schrieb:

stimmt, daher mache ich das so:

1
2
3
4
5
6
7
8
recalStartTime()
{

# die fuehrenden Nullen bei einstelligen Zahlen abschneiden
MIN=`date +%M`
MIN=${MIN#"0"}
SEK=`date +%S`
SEK=${SEK#"0"}

Probier mal:

1
2
min=$(date +%1M)
sek=$(date +%1S)

Backticks sind schlecht lesbar, weniger portabel und schlecht zu schachteln. Shellvariablen per Konvention klein. Date hat Formatierungsmöglichkeiten um führende Nullen zu eliminieren.

1
2
if [ $MIN -ge 0 -a $MIN -lt 15 ] 
	then

Arithmetische Tests in runden Klammern:

1
2
if (( min >= 0 && min < 15 ))
	then

In den doppelten runden Klammern kann auf das $ verzichtet werden.

1
		L=$(( $(( 14 - $MIN )) * 60 + $(( 60 - $SEK )) ))

Innerhalb doppelter runder Klammern müssen diese nicht wiederholt werden:

1
		l=$(((14 - min) * 60 + (60 - sek)))

Case-Statements:

Wenn Du 0-59 Minuten/Sekunden durch 15 teilst, dann bekommst Du 4 Fälle von 0 bis 3.

Statt eines Casestatements kommt dann auch ein Array in Frage - habe aber nicht weiter den Code analysiert.

Statt die Zeit selbst zu messen könnte man das aber auch in einem Cronjob abhandeln. Oder mit einem systemd-timer, aber da braucht man immer gleich 2 Files für jeden Timer, das ist nicht wartungsfreundlich.

frostschutz

Avatar von frostschutz

Anmeldungsdatum:
18. November 2010

Beiträge: 7790

Andere Möglichkeit wäre über die Unixtime zu gehen und Modulo.

Sekunden seit der letzten / bis zur nächsten vollen Viertelstunde:

1
2
3
4
5
6
$ date &&
  echo $(($(date +%s) % (15*60))) &&
  echo $((15*60 - $(date +%s) % (15*60)))
Mon Feb 26 09:33:45 CET 2024
225
675

Mit date %N könnte man dann auch noch höhere Genauigkeit erreichen. Aber auf die Hunderstel-Sekunde wirds nicht ankommen...?

micneu

Avatar von micneu

Anmeldungsdatum:
19. Januar 2021

Beiträge: 832

Wohnort: Hamburg

1. warum Script 1 nicht in einem cronjob laufen lassen? 2. Script 2 würde ich als systemd laufen lassen mit inotifywait ein Verzeichnis überwachen auf Änderungen (habe ich für ein SMS-Gateway aktuell am Laufen.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17622

Wohnort: Berlin

micneu schrieb:

2. Script 2 würde ich als systemd laufen lassen mit inotifywait ein Verzeichnis überwachen auf Änderungen (habe ich für ein SMS-Gateway aktuell am Laufen.

Hat banause schon gemacht (inotify), wie im Eingangspost zu lesen, und war nicht zuverlässig.

Bei Spielereien mit inotify hatte ich auch nicht den Eindruck, dass das zuverlässig sei.

banause

(Themenstarter)

Anmeldungsdatum:
17. November 2009

Beiträge: 301

Danke für Eure Tipps.

Melde mich mit den Resultaten.

Gruß,

banause

Antworten |