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?
Chandler B. schrieb:> Kann ich das auch über "cron" machen?
Ja.
Chandler B. schrieb:> Aber muss ich dann eingeloggt sein, damit das ausgeführt wird?
Nein.
LG, Sebastian
Chandler B. schrieb:> Kann ich das auch über "cron" machen?
Was heißt "auch"? Cron ist eigentlich exakt dafür gemacht.
> Aber muss ich dann eingeloggt sein, damit das ausgeführt wird?
Das ist ganz unabhängig davon, ob du eingeloggt bist.
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
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
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
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.
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.
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.
https://linux.die.net/man/5/crontab
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.
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".
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.
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:> 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?
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.
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.
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.
>> 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.
5. 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.
6. Hmmmms Ratschlag, absolute Pfade zu verwenden, ist absolut
richtig!!1!
7. 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.
8. 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!
Ein T. schrieb:> 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".
Kleine Korrektur dazu: Nicht MAIL, sondern MAILTO.
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. :-)
Hmmm schrieb:> Ein T. schrieb:>> 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".>> Kleine Korrektur dazu: Nicht MAIL, sondern MAILTO.
Huch, stimmt, Du hast natürlich Recht!
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.
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.
Frank M. schrieb:> Und in speedtest.sh als erstes Kommando:echo Start: `date`>> Und am Ende:echo End: `date`>> (Achtung das sind Backticks um date)
Man kann auch $(date) schreiben. Das macht das gleiche.
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:
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.
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.
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.
Ein T. schrieb:>> 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.
Es gibt auch bei `` die Möglichkeit zu verschachteln durch Escapen, aber
das macht's auch nicht gerade hübscher.
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. ;-)
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"
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.
Sheeva P. schrieb:> Ein T. schrieb:>>>chmod ugo+x speedtest.sh> chmod a+x speedtest.sh
Die beiden Vorschläge sind aber mit einem sehr breiten
Berechtigungspinsel gemalt.
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
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.
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!
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>
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.
>> 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?
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!
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.
Rolf M. schrieb:> Hmm, für mich nicht.
Sehe ich genauso. Die zusätzlichen Semikolons sind hyperfluid und tragen
meiner Meinung auch nicht zur Lesbarkeit bei.
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.
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.
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.
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.
Frank M. schrieb:> 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.
Ich werfe mal logger(1) in den Raum, um es sauber zu lösen.
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.
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.
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.
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.
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.
Rolf M. schrieb:> Dann sollte das Shebang allerdings auch nicht #!/bin/bash lauten, was es> hier aber tut.
Das siehe ich nicht so eng. Die Endung zeigt an, womit es laufen kann,
das Shebang zeigt an, womit es hier konkret laufen soll. Schließlich
ist /bin/sh in den meisten Fällen sowieso ein Symlink auf irgendeine
konkrete Shell.
Mich würde mal interessieren, woher dieser sonderbare Wunsch kommt, ein
Shell-Script extra mit /bin/{bash,dash,sh} laufen zu lassen.
Mir hat bis jetzt immer ein zuvor angewandtes:
chmod u=rx,go= filename
gereicht.
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:
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.
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.
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.