raspberry pi shell-script automatisch ausführen lassen wenn keiner eingeloggt ist

OP #7610879
Lesenswert?

Hallo, ich habe ein kleines shell-script auf einem raspberry pi erstellt. Wenn ich dieses manuell ausführe (bin über SSH) eingeloggt, funktioniert es auch so wie erwartet.

Jetzt möchte ich das ganze aber automatisch alle X stunden ausführen lassen. Dabei bin ich nicht eingeloggt. Was muss ich dafür verwenden? Kann ich das auch über "cron" machen? Sowie ich das verstanden habe, kann man dort automatische Ausführungen für jeden Benutzer einstellen? Aber muss ich dann eingeloggt sein, damit das ausgeführt wird?

OP #7611664
Lesenswert?

Hallo, ganz so wie gedacht funktioniert es bei mir doch noch nicht

crontab -e: [code] 0 */3 * * * cd speedtest && sh speedtest.sh [code] (zwischen /3 und cd speedtest soll 3x) es soll alle 3 Stunden in den Ordner speedtest gewechselt werden und das skript speedtest.sh ausgeführt werden

speedtest.sh: [code] #!/bin/bash

if ! [ -e speedtest.csv] then speedtest-cli --csv --csv-header >> speedtest.csv fi

speedtest-cli --csv --secure >> speedtest.csv [code]

in speedtest.csv sehe ich aber nur den ersten Eintrag. also nicht alle 3 Stunden. Und der wurde am 25.01. um 14:16 Uhr gemacht (also auch nicht volle Stunde)

Wenn ich speedtest.sh selber noch einmal trigger, wird der nächste Eintrag unten drangehangen. Auch wenn ich crontab -e: [code] */2 * * * * cd speedtest && sh speedtest.sh [code] (zwischen /2 und cd speedtest soll 4x) Wird alle 2 Minuten eine Messung in speedtest.csv drangehangen

OP #7611685
Lesenswert?

Sebastian W. schrieb:

funktioniert? Seltsam ...

Ja

so ist es aus crontab herauskopiert (und nicht mehr abgetippt wie oben) ist aber das selbe (zumindest sehe ich keine unterschied)

1
#0 */3 * * * cd speedtest && sh speedtest.sh
2
*/2 * * * * cd speedtest && sh speedtest.sh

Also die obere zeile ist jetzt auskommentiert, da ich die untere zeile zum Testen reingenommen habe

OP #7612172
Lesenswert?

Sebastian W. schrieb:

Chandler B. schrieb:

Also die obere zeile ist jetzt auskommentiert, da ich die untere zeile zum Testen reingenommen habe

Ich kann mir nur vorstellen, dass beim ersten Test das Zeilenende fehlte. Kommentiere mal die zweite Zeile aus. Funktioniert es dann nach wie vor nicht?

LG, Sebastian

Hallo, das ich komme da irgendwie nicht weiter.

1
#run speedtest everyday all 3 hours
2
0 */3 * * * cd speedtest && sh speedtest.sh

Ich habe es wie folgt getestet. Ich habe nur noch diese eine Befehlszeile drinnen. Da bin ich einmal mit dem Kursor nach ganz vorne gegangen und habe die 0 mit */2 getauscht und */3 mit * (also alle 2 minuten) -> funktioniert Dann bin ich wieder mit dem Cursor zu den stellen gegangen und habe das */2 mit der 0 und das erste sternchen dann mit */3 getauscht. Also zeilenende oder so habe ich gar nichts geändert. Jetzt habe ich vorhin nachgeschaut und es ist wieder nur die Headerzeile drinn.

Gibt es noch eirgeneinen Logbefehl, den ich hinterlegen kann, ob es ausgeführt worden ist, oder ob evtl. irgendein Fehler vorliegt? Aber ganz verstehe ich nicht, warum es nicht funktioniert. Auch als ich das mit alle 2 Minuten getstet habe, habe ihc mich komplett ausgeloggt. Und es hat trotzdem funktioniert.

#7612187
Lesenswert?

anstatt einen cd speedtest & vorn dranzuhaengen, wobei nicht klar ist, von welchem Verzeichnis aus Du das betrachtest, wuerde ich sinnvollerweise stattdessen den Befehl mit vollem Pfad eintragen.

Harry L. schrieb:

Statt ohne Sinn und Verstand planlos irgendwelche Einstellungen zu probieren, könnte man ja einfach mal in die Dokumentation schauen.

das ausserdem auch noch.

OP #7612189
Lesenswert?

Harry L. schrieb:

Statt ohne Sinn und Verstand planlos irgendwelche Einstellungen zu probieren, könnte man ja einfach mal in die Dokumentation schauen. Da steht auch detailliert drin, welche Felder welche Bedeutung haben.

1
    minute
2
    0-59
3
    hour
4
    0-23
5
    day of month
6
    1-31
7
    month
8
    1-12 (or names, see below)
9
    day of week
10
    0-7 (0 or 7 is Sun, or use names) 
11
A field may be an asterisk (*), which always stands for "first-last".

Das steht in der man. also für mich ist, wenn

1
*/2 * * * *
1
minute: */2 -> alle 2 minuten
2
hour: * -> jede stunde
3
day of month: * -> jeder Tag
4
month: * -> jeder monat
5
day of week: * -> Jeder Wochentag
1
0 */3 * * *
1
minute: 0 -> jede 0te minute
2
hour: */3 -> jede dritte stunde
3
day of month: * -> jeder Tag
4
month: * -> jeder monat
5
day of week: * -> Jeder Wochentag

Bsp. von der Seite

1
# run five minutes after midnight, every day
2
5 0 * * *       $HOME/bin/daily.job >> $HOME/tmp/out 2>&1

nur das ich nicht 5 minuten nach Mitternacht haben möchte, sonder alle 3 Stunden

#7612193
Lesenswert?

Chandler B. schrieb:

1
> #!/bin/bash
2
> 
3
> if ! [ -e speedtest.csv]
4
> then
5
>   speedtest-cli --csv --csv-header >> speedtest.csv
6
> fi
7
> 
8
> speedtest-cli --csv --secure >> speedtest.csv
  1. Fehlendes Semikolon am Ende der if-Zeile.

  2. Zum Debuggen Deines Problems ist etwas, das sich bei vorhandener Datei anders verhält als bei nicht vorhandener, extrem ungünstig. Warum fängst Du nicht mit einem simplen "date >> test.txt" an, um erstmal zu sehen, ob es wie gewollt gestartet wird?

Chandler B. schrieb:

cd speedtest

Bei sowas immer absolute Pfade verwenden, erspart Kopfschmerzen.

Chandler B. schrieb:

Gibt es noch eirgeneinen Logbefehl, den ich hinterlegen kann, ob es ausgeführt worden ist, oder ob evtl. irgendein Fehler vorliegt?

Cron kann sogar Mails verschicken, steht alles in den Man-Pages.

OP #7612212
Lesenswert?

Hmmm schrieb:

  1. Fehlendes Semikolon am Ende der if-Zeile.

laut https://openbook.rheinwerk-verlag.de/linux/linux_kap11_005.html muss das semikolon nur, wenn das "then" sich in der selben zeile befindet

Hmmm schrieb:

  1. Zum Debuggen Deines Problems ist etwas, das sich bei vorhandener Datei anders verhält als bei nicht vorhandener, extrem ungünstig. Warum fängst Du nicht mit einem simplen "date >> test.txt" an, um erstmal zu sehen, ob es wie gewollt gestartet wird?

Das skript macht ja an für sich das was es soll. Wenn ich es manuell ausführe, erstellt es eine Datei und erstellt die erste messung. Wenn eine Datei schon existiert, wird nur eine weitere Messung angehangen.

Wenn ich das skript alle 2 Minuten ausführe funktioniert es genauso.

Das Problem ist (warum auch immer), wenn ich es alle 3 Stunden trigger.

Hmmm schrieb:

Chandler B. schrieb:

cd speedtest

Bei sowas immer absolute Pfade verwenden, erspart Kopfschmerzen.

habe jetzt

1
0 */3 * * * sh speedtest/speedtest.sh

damit wird die csv datei zwar nicht im Ordner speedtest erstellt, aber das ist mir erstmal egal, solange es überhaupt mal funktioniert. Auch hier habe ich es einmal mit alle 2 Minuten getestet. Da funktioniert es. Werde ich morgen sehen, ob es geklappt hat.

#7612213
Lesenswert?

Ein T. schrieb:

Nachdem die Damen und Herren nun ausführlich auf den Cron-Daemon hingewiesen haben, möchte ich daran erinnern, daß es auf vielen modernen Distributionen heutzutage noch eine andere Möglichkeit gibt: nämlich die systemd-Timer.

Das hilft dem TO jetzt aber wirklich richtig gut.

@TO

Schreibe es mal so:

1
0 */3 * * *  cd <voll qualifizierter Pfad zu speedtest> && speedtest.sh

Für das Pfadwechselkommando würde ich den vollen Pfad angeben. Wenn dieser Pfadwechsel fehl schlägt, also z.B. das Verzeichnis nicht vorhanden ist, dann wird der Teil nach && gar nicht ausgeführt. Das sh vor Deinem Script brauchst Du nicht, denn Du legst in der ersten Scriptzeile fest mit welcher Shell Dein Script ausgeführt werden soll. Allerdings muß Dein Script Ausführungsrechte haben. Das geht ganz einfach im Terminal mit

1
chmod ugo+x speedtest.sh

Ansonsten wenn Du den Pfadwechsel nur ausführst, um in das Verzeichnis des Scriptes zu gelangen, dann schreibe vor speedtes.sh einfach den vollständigen Pfad zum Script.

#7612219
Lesenswert?

Chandler B. schrieb:

muss das semikolon nur, wenn das "then" sich in der selben zeile befindet

Stimmt tatsächlich, Semikolon oder Newline. Bin noch nie auf die Idee gekommen, das then in eine separate Zeile zu packen.

Chandler B. schrieb:

Das skript macht ja an für sich das was es soll.

Das Gesamtkonstrukt tut nicht, was es soll. Also versucht man, den Fehler systematisch einzugrenzen, indem man z.B. prüft, ob und wann das Script gestartet wird.

Es könnte schliesslich auch sein, dass Dein speedtest-Tool sich unter bestimmten Umständen (z.B. kein User eingeloggt) anders verhält.

Chandler B. schrieb:

Bei sowas immer absolute Pfade verwenden, erspart Kopfschmerzen.

habe jetzt 0 */3 * * * sh speedtest/speedtest.sh

Auch das ist kein absoluter Pfad.

#7612232
Lesenswert?

Hmmm schrieb:

Chandler B. schrieb:

1
>> #!/bin/bash
2
>>
3
>> if ! [ -e speedtest.csv]
4
>> then
5
>>   speedtest-cli --csv --csv-header >> speedtest.csv
6
>> fi
7
>>
8
>> speedtest-cli --csv --secure >> speedtest.csv
9
>
10
>
  1. Fehlendes Semikolon am Ende der if-Zeile.

Das wäre schöner, spielt für die Funktion aber keine Rolle.

Chandler B. schrieb:

cd speedtest

Bei sowas immer absolute Pfade verwenden, erspart Kopfschmerzen.

True.

Chandler B. schrieb:

Gibt es noch eirgeneinen Logbefehl, den ich hinterlegen kann, ob es ausgeführt worden ist, oder ob evtl. irgendein Fehler vorliegt?

Cron kann sogar Mails verschicken, steht alles in den Man-Pages.

  1. Jedesmal, wenn Cron einen Cronjob ausführt, wird dazu ein Logeintrag in der Datei /var/log/syslog erzeugt.

  2. Die Crontabs sollte man nicht direkt mit dem Editor bearbeiten, sondern mit dem Kommandozeilenbefehl "crontab -e", der auf Debian-basierten Systemen per Default den Editor nano(1) oder jenen aufruft, der in der Umgebungsvariablen EDITOR konfiguriert ist. Das Programm crontab(1) überprüft dabei, ob die vom Editor gespeicherte Crontab korrekt formatiert ist (also nicht, ob die darin aufgerufenen Programme vorhanden und ausführbar sind), bevor es die Crontab installiert. Wenn das Format der vom Editor ausgegebenen Crontab inkorrekt ist, erzeugt crontab(1) eine Ausgabe in der Shell und fragt dann, ob es den Editierversuch wiederholen soll. Bei der Antwort "y" wird wieder der Editor in $EDITOR gestartet, bei der Antwort "n" wird crontab(1) die defekte Crontab in einer Datei in /tmp ablegen, den Pfad zu dieser Datei ausgegeben und sich danach beenden. crontab(1) findet auch keine Permission-Probleme, sondern überprüft ausschließlich das Format der neuen Crontab.

  3. Wenn das aufgerufende Programm etwas auf STDOUT oder STDERR ausgibt und diese beiden Streams nicht umgeleitet werden, oder das Skript einen Fehler zurückgibt -- also: der Rückgabewert des Programms ungleich 0 ist -- dann erzeugt Cron eine E-Mail an den Besitzer der Crontab (bei der systemweiten Crontab natürlich "root" (siehe auch unter 5.)) und versucht, sie mit dem installierten Mail Transport Agent (MTA) zuzustellen. Wenn das nicht funktioniert, weil kein MTA installiert ist, wird ein Logeintrag wie "(CRON) info (No MTA installed, discarding output)" in /var/log/syslog erzeugt. Wenn ein MTA installiert ist, dann werden die Mails per Default in /var/mail/<username> abgelegt, für die systemweite Crontab also in /var/mail/root.

  4. In der jeweiligen Crontab selbst kann man auch einen anderen (eventuell externen) Empfänger in der Variablen mit der Variablen MAIL konfigurieren, zum Beispiel in einer Zeile "MAIL=hab@ich.net". Voraussetzung ist natürlich auch hier, daß ein funktionsfähiger MTA installiert und zudem dort mindestens ein Smarthost konfiguriert ist.

  5. Hmmmms Ratschlag, absolute Pfade zu verwenden, ist absolut richtig!!1!

  6. Bei mir funktioniert die Crontab-Zeile

1
* */3 * * *    date >> /tmp/datum.txt

übrigens vollkommen problemlos. Mein Verdacht ist, daß der TO irgendeinen Tippfehler eingebaut hat. Das sollte sich mit "crontab -e" allerdings sehr leicht vermeiden lassen.

  1. Wie alle anderen Programme, sollten auch Cronjobs idealerweise mit den geringstmöglichen Permissions laufen, also nicht unbedingt als root, wenn sie dessen Privilegien nicht brauchen.

HTH!

#7612269
Lesenswert?

Hans schrieb:

Ein T. schrieb:

Nachdem die Damen und Herren nun ausführlich auf den Cron-Daemon hingewiesen haben, möchte ich daran erinnern, daß es auf vielen modernen Distributionen heutzutage noch eine andere Möglichkeit gibt: nämlich die systemd-Timer.

Das hilft dem TO jetzt aber wirklich richtig gut.

Da hast Du Recht, die Erinnerung richtete sich aber primär an die Mitleser.

Allerdings muß Dein Script Ausführungsrechte haben. Das geht ganz einfach im Terminal mit

1
chmod ugo+x speedtest.sh

Nunja, der TO sagt ja, mit anderen Einträgen in den Datums- und Zeitfeldern der Crontab würde dasselbe Skript funktionieren. Das würde es jedoch nicht, wenn die Dateirechte nicht korrekt gesetzt wären. Es bleibt mysteriös. :-)

Moderator Persönliche Seite #7613383
Lesenswert?

Hans schrieb:

cd <voll qualifizierter Pfad zu speedtest> && speedtest.sh

Ich würde sogar noch weiter gehen:

1
cd <voll qualifizierter Pfad zu speedtest> && ./speedtest.sh >>/tmp/speedtest.log 2>&1

Beachte: "./" vor speedtest.sh! Das ist wichtig, weil cron das aktuelle Arbeitsverzeichnis gar nicht im PATH hat!

Und in speedtest.sh als erstes Kommando:

1
echo Start: `date`

Und am Ende:

1
echo End: `date`

(Achtung das sind Backticks um date)

Zwischen den beiden Zeitausgaben in speedtest.log stehen dann eventuell enstandene Fehlermeldungen.

#7613400
Lesenswert?

Ein T. schrieb:

Allerdings muß Dein Script Ausführungsrechte haben. Das geht ganz einfach im Terminal mit 1chmod ugo+x speedtest.sh

Nunja, der TO sagt ja, mit anderen Einträgen in den Datums- und Zeitfeldern der Crontab würde dasselbe Skript funktionieren. Das würde es jedoch nicht, wenn die Dateirechte nicht korrekt gesetzt wären. Es bleibt mysteriös. :-)

Er wird es aber auch da mit sh speedtest.sh eintragen. Das sh am Anfang kann man aber getrost weg lassen, wenn das Script Ausfgührungsrechte hat.

Moderator Persönliche Seite #7613411
Lesenswert?

Hans schrieb:

Das sh am Anfang kann man aber getrost weg lassen, wenn das Script Ausfgührungsrechte hat.

Beachte, dass das aktuelle Arbeitsverzeichnis im Allgemeinen nicht im Pfad ist. Wenn Du also bei

1
sh mein-script.sh

das "sh" weglassen willst, musst Du (neben der Beachtung der Ausführungsrechte) auch den Pfad angeben, also:

1
./mein-script.sh
#7613504
Lesenswert?

Hans schrieb:

Er wird es aber auch da mit sh speedtest.sh eintragen. Das sh am Anfang kann man aber getrost weg lassen, wenn das Script Ausfgührungsrechte hat.

Mit dem vorangestellten "sh" kann er sich neben den Ausführrechten auch die explizite Pfadangabe "./" sparen, auf die Frank M. (ukw) hingewiesen hat. Es wäre dann immer noch etwas unglücklich, daß das Skript selbst "/bin/bash" in der Shebangzeile hat, also ein Bash-Skript ist, das dann jedoch von Cron mit der Shell "sh" ausgeführt würde. Eine saubere Systempflege würde solcherlei Fehlerquellen natürlich vermeiden.

#7613518
Lesenswert?

Ein T. schrieb:

Mit dem vorangestellten "sh" kann er sich neben den Ausführrechten auch die explizite Pfadangabe "./" sparen, auf die Frank M. (ukw) hingewiesen hat. Es wäre dann immer noch etwas unglücklich, daß das Skript selbst "/bin/bash" in der Shebangzeile hat, also ein Bash-Skript ist, das dann jedoch von Cron mit der Shell "sh" ausgeführt würde.

Man könnte natürlich statt sh auch bash davor schreiben, um dafür zu sorgen, dass es auch mit dieser ausgeführt wird.

Eine saubere Systempflege würde solcherlei Fehlerquellen natürlich vermeiden.

Dabei muss man insbesondere bedenken, dass zumindest bei Debian und darauf basierenden Systemen die sh in der Regel ein Symlink auf die dash ist und nicht auf die bash.

#7613520
Lesenswert?

Rolf M. schrieb:

Frank M. schrieb:

Und am Ende:echo End: date

(Achtung das sind Backticks um date)

Man kann auch $(date) schreiben. Das macht das gleiche.

Allerdings kann $() korrekt ineinander verschachtelt werden und ist meiner persönlichen Meinung nach auch besser lesbar. Das Problem mit den Backticks zeigt Frank ja schon: da muß man für unbedarfte Nutzer nochmals extra hinzu schreiben, daß das Backticks und keine Singlequotes sind, und die besonders unbedarften Benutzer wissen vielleicht auch nicht, was Backticks sind.

Moderator Persönliche Seite #7613548
Lesenswert?

Ein T. schrieb:

Allerdings kann $() korrekt ineinander verschachtelt werden und ist meiner persönlichen Meinung nach auch besser lesbar.

Stimmt schon, $() ist lesbarer. Ich schreibe oft noch die Backticks, weil ich das in den 80ern so gelernt habe. Damals gab es die Schreibweise mit $() noch nicht. Die Bourne-Shell kannte diese jedenfalls noch nicht.

Meiner Erinnerung nach war $() zunächst eine bash-spezifische Erweiterung, wurde dann aber später in den POSIX-Standard mit aufgenommen, so dass $() heute eigentlich jede Shell versteht. Man mag mich korrigieren, wenn mich meine Erinnerung täuscht. ;-)

OP #7613718
Lesenswert?

Frank M. schrieb:

Ich würde sogar noch weiter gehen:cd <voll qualifizierter Pfad zu speedtest> && ./speedtest.sh >>/tmp/speedtest.log 2>&1

Beachte: "./" vor speedtest.sh! Das ist wichtig, weil cron das aktuelle Arbeitsverzeichnis gar nicht im PATH hat!

Und in speedtest.sh als erstes Kommando:echo Start: date

Und am Ende:echo End: date

(Achtung das sind Backticks um date)

Zwischen den beiden Zeitausgaben in speedtest.log stehen dann eventuell enstandene Fehlermeldungen.

Habe es heute Mittag zunächst angepasst

1
#!/bin/bash
2
echo START: `date`
3
if ! [ -e speedtest.csv ]
4
then
5
        echo "file does not exist -> create fie speedtest.csv"
6
        speedtest-cli --csv --csv-header --bytes --secure >> speedtest.csv
7
fi
8

9
speedtest-cli --csv --bytes --secure >> speedtest.csv
10
echo END: `date`

und im cron

1
0 */3 * * * sh /home/speedtest/speedtest.sh >> /home/cron.log 2>&1

Und in der Log konnte ich dann tatsächlich einen Error finden

1
GNU nano 5.4                                                                                                                        cron.log
2
START: Thu 29 Feb 18:00:01 CET 2024
3
file does not exist -> create fie speedtest.csv
4
ERROR: Unable to connect to servers to test latency.
5
END: Thu 29 Feb 18:00:04 CET 2024

Mit diesem Fehler konnte ich weitersuchen und habe öfters gelesen, dass es öfters vorkommt, dass die Server immer in der Vollen Stunde und Halben Stunde überlastet sind. Habe meinen cron-Befehl dann auf 8 Minuten nach (alle 3 Stunden) gändert.

1
8 */3 * * * sh /home/speedtest/speedtest.sh >> /home/cron.log 2>&1

Werde ich dann morgen sehen, ob es das Problem war. Aber zumindest weiß ich dann schonmal wo ich nachgucken kann, wenn ein Fehler passiert.

#7613783
Lesenswert?

Rolf M. schrieb:

Man könnte natürlich statt sh auch bash davor schreiben, um dafür zu sorgen, dass es auch mit dieser ausgeführt wird.

Der crond startet doch sowieso eine Shell für das Parsen und die Ausführung der Kommandozeile in Spalte 6. Warum dann nicht das speedtest.sh-Skript dort über den Befehl source in dieser Shell ausführen, anstatt noch eine weitere innere Shell zu starten? Oder übersehe ich etwas?

LG, Sebastian

#7613784
Lesenswert?

Foobar schrieb:

Wer weiß, was für einen cron er überhaupt hat? Evtl eine buggy systemd extension?

Sicher nicht. systemd hat eigene Möglichkeiten, Jobs periodisch auszuführen, nämlich die systemd.timer(5), die im Übrigen viel mehr Möglichkeiten bieten als schnöde Cronjobs. Wozu wäre eine "buggy systemd extension" dort denn nun bitte noch sinnvoll oder wünschenswert?

Zumal die Ausführungsumgebung bereits vom TO definiert wurde: es handelt sich um einen Raspberry Pi, also höchstwahrscheinlich um ein Debian GNU/Linux oder ein System, das darauf basiert. Dort ist meist der Cron-Daemon von Paul Vixie das Mittel der Wahl.

#7613788
Lesenswert?

Frank M. schrieb:

Ein T. schrieb:

Allerdings kann $() korrekt ineinander verschachtelt werden und ist meiner persönlichen Meinung nach auch besser lesbar.

Stimmt schon, $() ist lesbarer. Ich schreibe oft noch die Backticks, weil ich das in den 80ern so gelernt habe.

Same with me, aber das habe ich mir abgewöhnt. :)

Damals gab es die Schreibweise mit $() noch nicht. Die Bourne-Shell kannte diese jedenfalls noch nicht.

Absolutely true!

Meiner Erinnerung nach war $() zunächst eine bash-spezifische Erweiterung, wurde dann aber später in den POSIX-Standard mit aufgenommen, so dass $() heute eigentlich jede Shell versteht. Man mag mich korrigieren, wenn mich meine Erinnerung täuscht. ;-)

True. Meines Wissens können heute die Bourne Again Shell (bash), die Debian Almquist Shell (dash), die Korn Shell (ksh) und die Z Shell (zsh) das. Andere Shells kenne ich nicht und stelle fest, wie lang ich schon nicht mehr mit was anderem als Bash und Dash gearbytet habe. Huch!

#7613804
Lesenswert?

Chandler B. schrieb:

Habe es heute Mittag zunächst angepasst

1
> #!/bin/bash
2
> echo START: `date`
3
> if ! [ -e speedtest.csv ]
4
> then
5
>         echo "file does not exist -> create fie speedtest.csv"
6
>         speedtest-cli --csv --csv-header --bytes --secure >> 
7
> speedtest.csv
8
> fi
9
> 
10
> speedtest-cli --csv --bytes --secure >> speedtest.csv
11
> echo END: `date`
12
>

Bitte sei so lieb und mach hinter alle Zeilen außer "bash", "then" und "fi" jeweils ein Semikolon. Das ändert nichts an der Funktion, macht Dein Skript aber vermutlich nicht nur aus meiner Perspektive lesbarer.

Zudem würde ich für den Logeintrag der Endzeit auch noch einmal die Startzeit ausgeben, um den Zusammenhang zwischen den Logeinträgen sichtbar zu machen.

und im cron

1
> 0 */3 * * * sh /home/speedtest/speedtest.sh >> /home/cron.log 2>&1
2
>

Das wäre aus meiner Sicht ein Fehler, und wenn einer meiner Entwickler mir so etwas vorlegen würde, hätten wir ein sehr langes und sehr ernstes Gespräch.

Dein Skript ist ein Bash-Skript (die Shebang-Zeile lautet "#!/bin/bash", aber Du führst es mit "sh" aus. Das "sh" ist aber irgendetwas, das Dein System in den Verzeichnissen der Umgebungsvariablen $PATH findet, und muss daher keine Bash sein. Wenn Du dann in Deinem Skript Konstrukte benutzt, die nur in der Bash verfügbar sind, hast Du ein Problem.

Auch Deine Dateinamenerweiterung halte ich für, sagen wir, schwierig. Wenn ich Bash-Skripte schreibe, dann enden sie auf ".bash", wenn ich allgemeingültige Shellskripte schreibe, auf ".sh", entsprechend auch Skripte für die Korn- und die Z-Shell (".ksh" und ".zsh").

Warum? So ein UNIXoides System besteht aus drölfzig Zilliarden an Dateien. Je eindeutiger die benannt sind, desto einfacher ist es, sich einzufinden. Dabei geht es hier bisher nicht um technische Anforderungen, sondern um humane.

There are two hard things in computer science: cache invalidation, off-by-one errors, and naming things. Meine Anmerkungen in diesem Absatz betreffen den "naming things"-Teil. :)

Dann habe ich ein zweites Problem mit Deinem Ansatz, nämlich das Schreiben in /home. Sowas würde ein erfahrener Sysop einfach nicht machen, sorry. Es gibt für so etwas das Verzeichnis /var/log, und rate, wofür das da ist? Haargenau: für _var_iable _log_Daten.

Und in der Log konnte ich dann tatsächlich einen Error finden

1
> ERROR: Unable to connect to servers to test latency.
2
>

Ach, sieh an. :)

1
> 8 */3 * * * sh /home/speedtest/speedtest.sh >> /home/cron.log 2>&1
2
>

Werde ich dann morgen sehen, ob es das Problem war. Aber zumindest weiß ich dann schonmal wo ich nachgucken kann, wenn ein Fehler passiert.

Lessons learned: Unter Linux sind Logdateien wichtig und enthalten wertvolle Informationen, was passiert (ist).

Hast Du schon eine Idee für die Analyse und Visualisierung Deiner Logs?

#7613806
Lesenswert?

Sebastian W. schrieb:

Der crond startet doch sowieso eine Shell für das Parsen und die Ausführung der Kommandozeile in Spalte 6. Warum dann nicht das speedtest.sh-Skript dort über den Befehl source in dieser Shell ausführen, anstatt noch eine weitere innere Shell zu starten? Oder übersehe ich etwas?

"source" ist ein Bashism und obendrein dazu gedacht, Umgebungsvariablen in der laufenden Shell zu setzen. Wegen der potentiellen Seiteneffekte sollte man das nicht ohne Not benutzen!

#7613908
Lesenswert?

Sheeva P. schrieb:

Bitte sei so lieb und mach hinter alle Zeilen außer "bash", "then" und "fi" jeweils ein Semikolon. Das ändert nichts an der Funktion, macht Dein Skript aber vermutlich nicht nur aus meiner Perspektive lesbarer.

Hmm, für mich nicht. Sie würden mich eher irritieren, und ich würde mich fragen, warum da überall unnötige Semikolons sind. Ich kenne das von Shellskripten eher nicht, dass da jede Zeile mit einem Semikolon abgeschlossen wäre.

Moderator Persönliche Seite #7613923
Lesenswert?

Chandler B. schrieb:

Und in der Log konnte ich dann tatsächlich einen Error finden

Nur zur Info: Als Du noch nicht den Standard-Fehler-Ausgabekanal (stderr) in cron.log umgeleitet hast, hätte cron Dir eine Mail schicken müssen.

Grund: Immer wenn der zu startende Job etwas auf dem Standard-Ausgabekanal (stdout) oder Standard-Fehler-Ausgabekanal (stderr) ausgibt, schickt der cron eine lokale Mail mit dem Inhalt. Durch die neue Umleitung in cron.log unterlässt er das jetzt.

Wenn Du in der Shell also mal "mail" eingibst, sollten Dir Dutzende von Mails von Deinen vorhergehenden Versuchen entgegenwinken :-)

Voraussetzung ist natürlich, dass auf dem System zumindest ein minimales Mail-Paket installiert ist.

OP #7614295
Lesenswert?

Sheeva P. schrieb:

Auch Deine Dateinamenerweiterung halte ich für, sagen wir, schwierig. Wenn ich Bash-Skripte schreibe, dann enden sie auf ".bash", wenn ich allgemeingültige Shellskripte schreibe, auf ".sh", entsprechend auch Skripte für die Korn- und die Z-Shell (".ksh" und ".zsh").

leider weiß ich nicht, was genau der unterschied zwischen .bash und .sh ist. Was wäre denn jetzt hier richtig?

  • Das „Shebang“ entfernen?
  • Die Datei .bash nennen und mit bash aufrufen?

Sheeva P. schrieb:

Dann habe ich ein zweites Problem mit Deinem Ansatz, nämlich das Schreiben in /home. Sowas würde ein erfahrener Sysop einfach nicht machen, sorry. Es gibt für so etwas das Verzeichnis /var/log, und rate, wofür das da ist? Haargenau: für _var_iable _log_Daten.

Ok, da ich aber nicht so oft auf dem rasperry pi bin, hatte ich es direkt ins home gemacht, damit ich das sofort sehe und weiß das da was ist. Aber ja, es gibt bestimmt einen besseren Ort (in diesem fall /var/log) dafür.

Sheeva P. schrieb:

Hast Du schon eine Idee für die Analyse und Visualisierung Deiner Logs?

Das werde ich wahrscheinlich mit Python machen.

Frank M. schrieb:

Wenn Du in der Shell also mal "mail" eingibst, sollten Dir Dutzende von Mails von Deinen vorhergehenden Versuchen entgegenwinken :-)

Voraussetzung ist natürlich, dass auf dem System zumindest ein minimales Mail-Paket installiert ist.

Wie bekomme ich das denn heraus? Also wenn ich keine "richtige" E-Mailadresse hinterlegt habe, gäbe es dann etwas internes? Wenn ich mit Putty auf dem raspberry pi bin und "mail" eingebe, bekomme ich den fehler -bash: mail: command not found

Ein T. schrieb:

Nunja, der TO sagt ja, mit anderen Einträgen in den Datums- und Zeitfeldern der Crontab würde dasselbe Skript funktionieren. Das würde es jedoch nicht, wenn die Dateirechte nicht korrekt gesetzt wären. Es bleibt mysteriös. :-)

Das Problem war wahrscheilich die 0 bei den Minuten. Jetzt wo ich dort 8 Eingetragen habe, funktioniert es ohne Probleme (bisher). Also alle 8 minuten nach, alle 3 Stunden.

So kann ich es jetzt erstmal laufen lassen.

Moderator Persönliche Seite #7614386
Lesenswert?

Chandler B. schrieb:

Also wenn ich keine "richtige" E-Mailadresse hinterlegt habe, gäbe es dann etwas internes?

Ja, der cron schickt den Output nach user@localhost.

Wenn ich mit Putty auf dem raspberry pi bin und "mail" eingebe, bekomme ich den fehler -bash: mail: command not found

Dann ist auch kein Mailpaket drauf und der cron konnte Dir dann auch nicht den Output per Mail schicken. Genau wie ich schon sagte:

Frank M. schrieb:

Voraussetzung ist natürlich, dass auf dem System zumindest ein minimales Mail-Paket installiert ist.

Aber egal: Ich selbst finde die Lösung mit den Log-Dateien sowieso praktischer.

Moderator Persönliche Seite #7614389
Lesenswert?

Chandler B. schrieb:

Aber ja, es gibt bestimmt einen besseren Ort (in diesem fall /var/log) dafür.

Ich persönlich hatte ja eine Logdatei unter /tmp vorgeschlagen - aber nur deswegen, weil Du uns nicht verraten hast, unter welcher User-ID Dein cron-Job überhaupt läuft. /tmp macht da keine Probleme, unter /var/log kann kein normaler User etwas anlegen.

Aber da Du ja dann tatsächlich als Logdatei /home/cron.log gewählt hast, wo ein normal sterblicher User auch nix schreiben kann, vermute ich mal, dass der Job als User root läuft. Dann hättest Du natürlich Schreibberechtigung unter /var/log.

#7615877
Lesenswert?

Chandler B. schrieb:

leider weiß ich nicht, was genau der unterschied zwischen .bash und .sh ist. Was wäre denn jetzt hier richtig?

  • Das „Shebang“ entfernen?
  • Die Datei .bash nennen und mit bash aufrufen?

Die Shebang-Zeile zu entfernen, ist sicherlich keine gute Idee. Aber fangen wir ungewöhnlicherweise mit dem Anfang an...

Auf vielen Linux-Systemen ist /bin/sh ein symbolischer Link auf /bin/bash, also wird ein Aufruf von "sh", wie Du ihn in Deiner Crontab verwendest, die Bash aufrufen. Auf Debian-basierten Systemen ist das allerdings nicht so, dort ist /bin/sh ein Symlink auf /bin/dash, die Debian Almquist Shell, die leider in einigen Bereichen nicht mit der Bash kompatibel ist. Dafür ist sie etwas performanter und benötigt weniger Systemressourcen, deswegen haben die Leute bei Debian das so gemacht.

Du hingegen rufst mit Deiner Shebang-Zeile die Bash auf. Wenn jemand wie ich dieses Skript bearbeitet und diese Shebang-Zeile sieht, gehe ich davon aus, daß die Bash benutzt wird und ich daher auch Bash-Besonderheiten (Bashisms) benutzen kann, also die Möglichkeiten, welche zwar die Bash bietet, und die andere Shells womöglich aber nicht bieten. Solange ich keine Bashisms nutze, ist es kein Problem, das Skript mit "sh", also "/bin/sh" aufzurufen. Aber da Deine Shebang-Zeile ausssagt, daß zur Ausführung die Bash benutzt wird, heißt das für mich, daß ich Bashisms benutzen darf. Und die fallen mir dann sofort auf die Füße, wenn das Skript nicht von der Bash ausgeführt wird.

Also kannst Du entweder Deine Shebang-Zeile durch "#!/bin/sh" ersetzen und dadurch signalisieren, daß das Skript keine Bashisms nutzen darf, oder die Shebang-Zeile so lassen, wie sie ist, und den Aufruf Deines Skripts mit "sh" in der Crontab durch "bash" oder noch besser "/bin/bash" ersetzen und das Skript dann eindeutig mit der Bash aufrufen.

#7615957
Lesenswert?

Um's nochmal kurz un knapp zu machen: (Ich nehme mal an, auf deinem Raspi läuft ein debian-basiertes System)

1
./speedtest.sh

-> Skript läuft in der bash, weil der Shebang das so vorgibt. Die Dateinamens-Endung '.sh' ist dann etwas irritierend, aber für die Ausführung des Skripts nicht relevant.

1
sh speedtest.sh

-> Skript läuft in der dash, weil du es explizit mit sh gestartet hast, das auf die dash verweist. Das passt zwar zur Dateinamens-Endung '.sh', aber nicht zu deinem Shebang, das eigentlich die bash will.

1
bash speedtest.sh

-> Skript läuft mit der bash, weil du es explizit damit gestartet hast.

Moderator Persönliche Seite #7615966
Lesenswert?

Rolf M. schrieb:

Die Dateinamens-Endung '.sh' ist dann etwas irritierend, aber für die Ausführung des Skripts nicht relevant. ... Das passt zwar zur Dateinamens-Endung '.sh', aber nicht zu deinem Shebang, das eigentlich die bash will.

Warum so kompliziert?

Warum muss die Endung zu der Shell passen, mit der man es ausführt? Meiner Meinung nach muss die Endung lediglich zu der Shell passen, mit der man es ausführen kann.

Oder mit anderen Worten:

Solange das Script keine bashisms enthält, verdient es auch die Endung ".sh", denn es ist vollkommen irrelevant, mit welcher (Posix-kompatiblen) Shell man es tatsächlich ausführt.

Wenn's nur mit dash liefe, würde ich .dash wählen, wenn es nur mit bash liefe, würde ich .bash wählen. Wenn's mit allen liefe, dann ist .sh gerechtfertigt. Die Endung ".sh" ist sogar hilfreich, denn sie zeigt an, dass das Script kompatibel ist.

#7617652
Lesenswert?

Chandler B. schrieb:

dass die Server immer in der Vollen Stunde und Halben Stunde überlastet sind.

Werde ich dann morgen sehen, ob es das Problem war.

Na das ist ja 'ne fiese Erklärung.

Erinnere mich jetzt aber daran, in grauer Vorzeit - als richtige PCs noch viel, viel lahmer waren als ein RasPi heute - gab es den Tip cron-jobs die man ein mal täglich oder stündlich laufen haben wollte, besser nicht auf Mitternacht bzw. volle Stunden zu setzen, weil da die Systeme oft eh schon genug zu tun hatten.

Sheeva P. schrieb:

"source" ist ein Bashism und

Jetzt wollte ich schon widersprechen, aber das stimmt für ja für source tatsächlich, den (in der Praxis ohnehin fast ausschließlich geschriebenen) . gibt es aber mindestens seit der Bourne-Shell.

obendrein dazu gedacht, Umgebungsvariablen in der laufenden Shell zu setzen.

Das hingegen kann man so nicht stehen lassen, jedenfalls nicht im Zusammenhang mit shell-Skripten. In solchen dient es eigentlich vor allem als include-Statement.

#7617780
Lesenswert?

Frank M. schrieb:

Warum muss die Endung zu der Shell passen, mit der man es ausführt?

Die Endung ist doch dafür da, dass man weiß, mit welcher Shell es ausgeführt werden soll, wobei sh dann für "irgendeine POSIX-konforme Shell" steht.

Solange das Script keine bashisms enthält, verdient es auch die Endung ".sh", denn es ist vollkommen irrelevant, mit welcher (Posix-kompatiblen) Shell man es tatsächlich ausführt.

Dann sollte das Shebang allerdings auch nicht #!/bin/bash lauten, was es hier aber tut.

Moderator Persönliche Seite #7617965
Lesenswert?

Norbert schrieb:

Mich würde mal interessieren, woher dieser sonderbare Wunsch kommt, ein Shell-Script extra mit /bin/{bash,dash,sh} laufen zu lassen.

Ich benutze das Konstrukt nur, um ein Script mit -x zu starten, damit ich sehe, was es tut. Okay, ich könnte auch das Script editieren und ein "set -x" reinsetzen (und nachher wieder rausnehmen), aber für eine Ad-Hoc-Action ist das einfacher:

1
sh -x filename.sh

Mir hat bis jetzt immer ein zuvor angewandtes: chmod u=rx,go= filename gereicht.

Jepp, mache ich in der Regel auch so. Manchmal lasse ich auch die Endung ".sh" weg, weil mir dann egal ist, ob die ausführbare Datei ein Script oder ein ELF-Executable ist. Von welchem Typ die Datei letztendlich ist, bekommt, man ja mit "file" raus:

1
file filename
#7618631
Lesenswert?

Frank M. schrieb:

Rolf M. schrieb:

Dann sollte das Shebang allerdings auch nicht #!/bin/bash lauten, was es hier aber tut.

Das siehe ich nicht so eng.

Das sehe ich "enger" als die Endung, denn die ist nur informativer Natur, während das Shebang tatsächlich Einfluss auf das Verhalten des Systems hat.

Die Endung zeigt an, womit es laufen kann, das Shebang zeigt an, womit es hier konkret laufen soll.

Warum /soll/ das Skript mit was anderen laufen als dem, wofür es geschrieben ist? Welchen Vorteil soll das bringen? Entweder schreibe ich es für die Bash, dann will ich auch, dass es mit der Bash ausgeführt wird, oder ich schreiben es so, dass es egal ist, dann ist es eben auch egal.

Moderator Persönliche Seite #7618695
Lesenswert?

Rolf M. schrieb:

Das sehe ich "enger" als die Endung, denn die ist nur informativer Natur, während das Shebang tatsächlich Einfluss auf das Verhalten des Systems hat.

Nochmal zum Verständnis:

Wenn ich ein kompatibles Shell-Script mit der Endung ".sh" speichere, dann hat das Shebang überhaupt keinen "Einfluss auf das Verhalten des Systems". Schreibe /bin/sh, /bind/bash, /bin/dash oder /bin/ksh rein, es ändert nichts. Das Verhalten ist immer gleich.

Genau das meinte ich und nichts anderes.

Andersherum wird ein Schuh daraus:

Inkompatible Shell-Scripts würde ich niemals mit der Endung ".sh" versehen. Wenn ich bashisms nutzen würde, dann wäre bei mir die Endung .bash und das Shebang selbstverständlich /bin/bash.

P.S.

Meine Shell-Scripts schreibe ich so, dass sie in jeder Posix-kompatiblen Shell laufen. ICh nutze grundsätzlich keine bashisms oder andere Shell-Spezifika.

#7619016
Lesenswert?

Frank M. schrieb:

Rolf M. schrieb:

Das sehe ich "enger" als die Endung, denn die ist nur informativer Natur, während das Shebang tatsächlich Einfluss auf das Verhalten des Systems hat.

Nochmal zum Verständnis:

Wenn ich ein kompatibles Shell-Script mit der Endung ".sh" speichere, dann hat das Shebang überhaupt keinen "Einfluss auf das Verhalten des Systems". Schreibe /bin/sh, /bind/bash, /bin/dash oder /bin/ksh rein, es ändert nichts. Das Verhalten ist immer gleich. Genau das meinte ich und nichts anderes.

Nein, wenn du das Skript in der Art "./meinskript" aufrufst, wird die Shell verwendet, die im Shebang steht, ganz unabhängig von der Endung. Wenn du es POSIX-konform gestaltet hast, gibt es keinen Grund, über das Shebang dann die bash zu erzwingen. Und wenn du da stattdessen was angibst, was keine POSIX-konforme Shell ist, dann funktioniert dein Skript ggf. auch gar nicht. Das Shebang hat also sehr wohl einen Einfluss, ganz im Gegensatz zur Endung. Und das ist es, was ich meinte.

Andersherum wird ein Schuh daraus:

Inkompatible Shell-Scripts würde ich niemals mit der Endung ".sh" versehen. Wenn ich bashisms nutzen würde, dann wäre bei mir die Endung .bash und das Shebang selbstverständlich /bin/bash.

Ja, so sehe ich das auch. Und wenn ich keine bashisms nutze, verweist das Shebang selbstverständlich nicht auf /bin/bash, denn sonst hätte ich das Skript ja völlig umsonst POSIX-konform geschrieben und hätte auch gleich Bashisms nutzen können.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren