crontab bzw. cronjob läuft nicht

bivvo

Neues Mitglied
Thread Starter
Dabei seit
13.07.2021
Beiträge
21
Punkte Reaktionen
3
Sehr komisch - ich suche mir nen Wolf und hab zig Kombinationen ausprobiert > das Script wird einfach nicht ausgeführt.

Mein crontab sieht so aus:

Bash:
me@my-mac ~ % crontab -l
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed
17   *  *  *  * me        /Users/me/cron.sh

Und das Script cron.sh so:

Bash:
#!/bin/sh -e
xattr -c /Users/me/Documents/script.sh && /Users/me/Documents/script.sh -d

Habt ihr eine Idee? Ob jetzt mit xattr Befehl oder ohne, daran liegt es nicht.
 

Atalantia

Aktives Mitglied
Dabei seit
26.11.2009
Beiträge
1.702
Punkte Reaktionen
373
Versuch es mal mit einem plist file in LaunchAgent wäre ne Möglichkeit.
~/Library/LaunchAgents

Ist das sh File executable?
 

oneOeight

Aktives Mitglied
Dabei seit
23.11.2004
Beiträge
63.882
Punkte Reaktionen
13.053
xattr mit vollem Pfad ins Script.
Du weißt ja nicht was in $PATH steht, wenn es ausgeführt wird.

Und ja, cron ist unter MacOS seit etlichen Versionen depracated.
Also mach einen launchd job.
 

bivvo

Neues Mitglied
Thread Starter
Dabei seit
13.07.2021
Beiträge
21
Punkte Reaktionen
3
Top, danke. Versuche ich und melde mich.
 

bivvo

Neues Mitglied
Thread Starter
Dabei seit
13.07.2021
Beiträge
21
Punkte Reaktionen
3
Ich hab jetzt mal für launchd folgende plist angelegt:

XML:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.bivvo.crontab</string>

  <key>LowPriorityIO</key>
  <true/>

  <key>Program</key>
  <string>/usr/local/bin/cron.sh</string>

  <key>StartInterval</key>
  <integer>60</integer>

  <key>RunAtLoad</key>
  <true/>

  <key>EnvironmentVariables</key>
  <dict>
    <key>PATH</key>
    <string>/bin:/usr/bin:/usr/local/bin</string>
  </dict>

  <key>StandardErrorPath</key>
  <string>/Users/bivvo/Desktop/cron-err.txt</string>

  <key>StandardOutPath</key>
  <string>/Users/bivvo/Desktop/cron-ok.txt</string>

  <key>UserName</key>
  <string>bivvo</string>
</dict>
</plist>

Und das Script ist auch entsprechend da:

Bash:
% ls -al /usr/local/bin | grep cron
-rwxr-xr-x   1 root  wheel      162 13 Jan 22:49 cron.sh

Da ich im Script Homebrew Programme nutze, z.B. jq und swaks, habe ich diesen auch den Festplattenvollzugriff gegeben, wie auch bash und sh selbst - sonst würden wohl die Skripte gar nicht laufen.

Im Script habe ich eingebaut, dass die Verfügbarkeit von jq und swaks geprüft wird:

Bash:
# check for jq
jq --version >/dev/null 2>&1
readonly jq_ok=$?
[[ "$jq_ok" -eq 127 ]] && echo "fatal: jq not installed" && exit 2
[[ "$jq_ok" -ne 0 ]] && echo "fatal: unknown error in jq" && exit 2
# jq exists and runs ok

# verify jq version minimum 1.6
jqversion="$(echo \"$(jq --version)\" | grep -o '[0-9]*[\.][0-9]*')"
[[ $(echo $jqversion '<' 1.6 | bc -l) -eq 1 ]] && echo "fatal: jq version 1.6 required (installed: $jqversion)" && exit 2

# check for curl
curl --version >/dev/null 2>&1
readonly curl_ok=$?
[[ "$curl_ok" -eq 127 ]] && echo "fatal: curl not installed" && exit 2
# curl exists and runs ok

# check for swaks
swaks --version >/dev/null 2>&1
readonly swaks_ok=$?
[[ "$swaks_ok" -eq 127 ]] && echo "fatal: swaks not installed" && exit 2
# swaks exists and runs ok

Im cron-ok.txt auf dem Desktop bekomme ich ausschließlich folgenden Output:
Code:
fatal: jq not installed

Mir sind die Ideen ausgegangen, warum jq offenbar nicht ausgeführt werden kann. :-/
 

oglimmer

Aktives Mitglied
Dabei seit
16.11.2004
Beiträge
1.329
Punkte Reaktionen
238
bei mir installiert homebrew jq unter /opt/homebrew/bin/jq. In deinem PATH ist aber nur /bin:/usr/bin:/usr/local/bin

generell sollte man in Skripten die von cron oder launchd (oder sonst einem Scheduler) aufgerufen werden, immer alle(!) Pfade voll angeben, also so als ob PATH leer ist.

man kann über "which jq" sich anzeigen lassen, wo das Programm liegt und dann einfach den vollen Pfad im script verwenden.
 

oneOeight

Aktives Mitglied
Dabei seit
23.11.2004
Beiträge
63.882
Punkte Reaktionen
13.053
Ich kann auch nur noch mal wiederholen und betonen, gewöhn dir an in Scripten immer alle Befehle mit vollem Pfad einzubinden.

Das spart dann auch solche Aktionen es in die launchd plist zu schreiben.
Und vielleicht noch die Skripte besser benennen. cron.sh ist dann doch verwirrend und du weißt in einer Woche nicht mehr was es tut.
 

bivvo

Neues Mitglied
Thread Starter
Dabei seit
13.07.2021
Beiträge
21
Punkte Reaktionen
3
man kann über "which jq" sich anzeigen lassen, wo das Programm liegt und dann einfach den vollen Pfad im script verwenden.
Danke dir! Aktuell wird "which jq" korrekt ausgeführt und mir der Pfad angezeigt, wenn ich das Script manuell ausführe. Wenn ich es aber über den Daemon starte, ist die Ausgabe von "which jq" leer. Wenn ich "which" den Festplattenvollzugriff gebe, hilft das auch nicht. Hab's also wieder entfernt aus der Liste.

Herausforderung 1: offenbar ein Berechtigungsproblem (?)
Hab ich den Launcher am falschen Ort, wenn die plist unter Globale Daemons liegt? (btw. danke @Atalantia) Sollte es nicht eher zu User Agents wandern? Es gibt leider auch keine Fehlerausgabe, dass which nicht aufgerufen werden konnte o.ä. Daher schlussfolgere ich, er findet jq nicht.

Herausforderung 2: absolute Pfade variabel setzen und Programm aufrufen
Ich nutze ein Script, das auch auf anderen Linux-Systemen laufen soll, daher möchte ich ungern absolute Pfade von MacOS verwenden. Wie kann ich den vollen Pfad auslesen (mit which nehme ich an) und dann das Programm damit ausführen - inkl. etwaiger Parameter, die wiederum mit Variablen gefüllt sind? Meine Suche über stacksovervlow und google waren bisher nicht zielführend.

Beispiel:
Bash:
swakspath=$(which swaks)
...
swaks --from "$MAILFROM" --to "$MAILTO" --server "$MAILSERVER" --auth LOGIN --auth-user "$MAILUSER" --auth-password "$MAILPASS" --h-Subject "DEBUG TEST MAIL" --body "blobb." --silent "1"
 

oglimmer

Aktives Mitglied
Dabei seit
16.11.2004
Beiträge
1.329
Punkte Reaktionen
238
Ah, das script soll unter macOS und unter Linuxen laufen. Das ist wichtig zu wissen.
Dabei ist erstmal zu beachten, dass macOS für viele "standard Programme" uralte gammel Versionen ausliefert: grep, sed, awk, bash. Das muss man beachten, wenn es um cross macOS/Linux geht.

Du hast jetzt verschiedene Möglichkeiten das cross platform zu machen:

* du verlässt dich auf $PATH (auch wenn wir gesagt hatten, dass man das nicht machen soll, ist es trozdem eine Lösung des Problems)
* es gibt ein config file das nur die Pfade zu den Programmen beinhaltet. Nachteil: händisches pflegen von Pfaden, Vorteil: einfach und funktioniert.
* du schreibst code der versucht die Programme selbstständig im filesystem zu finden. Nachteil: kompliziert ;), Vorteil: geht automatisch

Ich "berate" dich gerne noch weiter, aber um dein Problem mal zu lösen, nehmen wir mal das erste.

So sah in deinem ersten Beitrag die crontab aus:

Code:
me@my-mac ~ % crontab -l
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed
17   *  *  *  * me        /Users/me/cron.sh

mach mal in deinem terminal

Code:
echo $PATH

bei mir kommt da raus:
/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin

dann nimm das was da rauskommt und packe es im crontab hinter PATH= (und zwar mit " vorne und hinten)

das wäre dann bei mir so:

Code:
me@my-mac ~ % crontab -l
SHELL=/bin/sh
PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin"
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed
17   *  *  *  * me        /Users/me/cron.sh

so ist dann der PATH mit den gleichen Werten gesetzt wie es auch deine interaktive shell hat.
 

bivvo

Neues Mitglied
Thread Starter
Dabei seit
13.07.2021
Beiträge
21
Punkte Reaktionen
3
Danke, @oglimmer, ist für mich Neuland auf MacOS.

PATH sieht so aus bei mir und ist, wie vorgeschlagen, gesetzt in crontab:

Code:
/opt/homebrew/opt/python@3.8/bin:/Users/daniel/opt/miniconda3/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/opt/python/libexec/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

Leider passiert einfach nichts. Befehl ist so ausführbar, habe copy & paste aus der crtntab-zeile gemacht - läuft. Aber automatisch durch crontab passiert gar nix.
 

oneOeight

Aktives Mitglied
Dabei seit
23.11.2004
Beiträge
63.882
Punkte Reaktionen
13.053
Dabei ist erstmal zu beachten, dass macOS für viele "standard Programme" uralte gammel Versionen ausliefert: grep, sed, awk, bash. Das muss man beachten, wenn es um cross macOS/Linux geht.
Eher wäre zu beachten, dass sich die BSD und die GNU Versionen unterschiedlich verhalten.
 

oneOeight

Aktives Mitglied
Dabei seit
23.11.2004
Beiträge
63.882
Punkte Reaktionen
13.053
Wie kann ich den vollen Pfad auslesen (mit which nehme ich an) und dann das Programm damit ausführen - inkl. etwaiger Parameter, die wiederum mit Variablen gefüllt sind?
Das schlägt fehl, wenn es nicht im PATH ist, denn which sucht auch darüber wie die Shell.

Musst du also im Script setzen, nicht im Crontab, der übergibt das anscheinend nicht.
 

bivvo

Neues Mitglied
Thread Starter
Dabei seit
13.07.2021
Beiträge
21
Punkte Reaktionen
3
> Das schlägt fehl, wenn es nicht im PATH ist, denn which sucht auch darüber wie die Shell.
Cool, dann weiß ich das für die Zukunft: PATH ergänzen, mit den Infos aus which und dann das Programm ausführen. Danke!

Aha, ich hab den error output in ein txt File umgeleitet. Cron läuft also, bringt aber folgenden Fehler:

Code:
/bin/sh: me: command not found

Sieht so aus, als suchen wir an der falschen Stelle.
Mir war nicht bewusst, dass wir keinen User angeben müssen:

Code:
18   *  *  *  * me    /Users/me/.../script.sh -d -p $PATH >> /Users/me/Desktop/err.txt 2>&1

Den PATH übergebe ich vorsorglich. Schadet nicht.
Wenn ich den User entferne, wird das Script aufgerufen, ich erhalte dann aber folgenden Fehler:

Code:
bash: ... script.sh: Operation not permitted

Zugriffsrechte sehen so aus:

Code:
-rwxr-xr-x   1 me  staff

Jetzt hab ich noch überall sichergestellt, dass "/bin/bash" hinterlegt ist > gleiches Ergebnis ("operation not permitted").

Jetzt fällt mir auch erst die Meldung "you have new mail" im Terminal auf:

Code:
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <PATH=/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/opt/python/libexec/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin>
X-Cron-Env: <LOGNAME=me>
X-Cron-Env: <USER=me>

Dieser Beitrag hat geholfen : cron den Festplattenvollzugriff gegeben.

Problem gelöst! Danke euch, für eure Hilfe.
 
Zuletzt bearbeitet:
Oben Unten