Launchd dazu bringen, Programmargumente korrekt zu lesen

Ich habe ein launchd-Skript, in dem der Befehl, den ich ausführen möchte, fehlerhaft ist (anscheinend ist das kein Wort, es ist jetzt) ​​und sich über unsachgemäße Verwendung beschwert.

Der spezifische Fehler, den ich erhalte, ist der Verwendungstext des Befehls, der im Systemprotokoll abgelegt wird. Daraus schließe ich, dass die anderen Informationen (Pfad zum Befehl, Timing usw.) in der plist korrekt analysiert werden, nur nicht die Optionen des Befehls.

Nach der Befehlsverwendung habe ich eine letzte Zeile:

18/11/2013 09:30:00.101 com.apple.launchd.peruser.501: (fake.lable.seti[33833]) Exited with code: 1

Aber das bedeutet nur "Ich habe mit einem Fehler beendet".

Ich weiß, dass launchd den Befehl von seinen Optionen trennt und in der Manpage über ProgramArguments informiert: "...Bitte beachten Sie: Viele Leute sind durch diesen Schlüssel verwirrt. Bitte lesen Sie execvp(3) sehr sorgfältig!..."

Nun, ich habe execvp(3) gelesen und bin nicht klüger geworden, also frage ich Sie sehr viel.

Normalerweise würde es beim Ausführen des Befehls vom Terminal so aussehen:

/Library/Application\ Support/BOINC\ Data/boinccmd --host localhost --passwd gobbledygook --project http://setiathome.berkeley.edu/ update

Das funktioniert wunderbar.

Und so habe ich es im Abschnitt Program/ProgramArguments meiner LaunchAgent-Liste aufgeteilt:

<key>Program</key>
    <string>/Library/Application Support/BOINC Data/boinccmd</string>
<key>ProgramArguments</key>
    <array>
        <string>--host localhost</string>
        <string>--passwd gobbledygook</string>
        <string>--project http://setiathome.berkeley.edu/ update</string>
    </array>

(Für die Aufzeichnung, ich hatte ursprünglich den Pfad zu boinccmd \escaped out, aber das funktioniert nicht, launchd entkommt Leerzeichen im Pfad für Sie)

Ich habe versucht, die Argumente weiter aufzuteilen:

<key>Program</key>
    <string>/Library/Application Support/BOINC Data/boinccmd</string>
<key>ProgramArguments</key>
    <array>
        <string>--host</string>
        <string>localhost</string>
        <string>--passwd</string>
        <string>gobbledygook</string>
        <string>--project</string>
        <string>http://setiathome.berkeley.edu/</string>
        <string>update</string>
    </array>

Aber auch das schien nicht zu funktionieren.

Wie immer bin ich mir sehr sicher, dass ich etwas so Einfaches vermisse.

Vielen Dank.


ANTWORTEN:

Die erste Zeile von ProgramArguments muss der Pfad zum Programm sein. Das war es, was mich stolperte und was wahrscheinlich mit dem Kommentar "... Bitte sehr sorgfältig lesen! ..." gemeint war :) Ich fand auch, dass ich die Argumente in ihre Bestandteile aufteilen musste. Wenn ich das alles an Ort und Stelle hatte, wirkt das Ganze wie ein Zauber. Ich danke Ihnen sehr.

<key>Program</key>
    <string>/Library/Application Support/BOINC Data/boinccmd</string>
<key>ProgramArguments</key>
    <array>
        <string>/Library/Application Support/BOINC Data/boinccmd</string>
        <string>--host</string>
        <string>localhost</string>
        <string>--passwd</string>
        <string>gobbledygook</string>
        <string>--project</string>
        <string>http://setiathome.berkeley.edu/</string>
        <string>update</string>
    </array>

Eine abschließende Bearbeitung für eine leicht verständliche Erklärung, WARUM dies sein sollte, siehe SirPavlovas Erklärung.

~W

Mit launchctl list com.label.plist kann ich sehen, dass launchd die richtigen Teile des Befehls erhält, um sie zusammenzusetzen. Ich dachte, es wäre vielleicht ein Problem im Zusammenhang mit dem --, aber anscheinend nicht.
Ich habe keine Antwort auf Ihr Problem, aber Ihr erstes Beispiel mit <string>--host localhost</string>wird definitiv nicht funktionieren. Denken Sie daran, wenn Sie eine Befehlszeile in eine Shell schreiben, hat diese keine Ahnung, was Teil einer Option und was ein reguläres Argument ist – sie teilt sich einfach bei Leerzeichen auf, bevor sie die Argumente an das ausgeführte Programm weitergibt. Es könnte auch hilfreich sein, wenn Sie den genauen Fehler anzeigen würden, boinccmdder gemeldet wird.
Habe meinen Beitrag bearbeitet, um zu sagen, was ich sehe. Nicht, dass es etwas nützen würde! Außerdem erhalte ich den gleichen Fehler, wenn ich die Optionen auf ihre Leerzeichen aufteile. Ich vermute, es ist das - das verursacht irgendwie das Problem.
Ich würde versuchen, nur Program oder ProgramArguments zu verwenden, nicht beides

Antworten (2)

Der ProgramSchlüssel gibt die auszuführende Datei an, und der ProgramArgumentsSchlüssel gibt die Argumente an, die an den ausführenden Prozess übergeben werden. Genau genommen können Sie einem Prozess beliebige Argumente übergeben, aber die Konvention ist, dass das erste Argument der Name sein sollte, mit dem der Prozess aufgerufen wurde, sodass die meisten Programme ihr erstes Argument ignorieren. Die auszuführende Datei ist offensichtlich eine notwendige Information, aber wenn der ProgramSchlüssel fehlt, gibt launchd aus ProgramArguments reiner Bequemlichkeit vor, denselben Wert wie das erste Argument zu haben .

Ihr erstes Beispiel startet boinccmd und gibt ihm Argumente, die dem Terminalbefehl entsprechen würden

--host\ localhost --passwd\ gobbledygook --project\ http://setiathome.berkeley.edu/\ update

was boinccmd mitteilt, dass Sie es als "--host localhost" aufgerufen und ihm nur zwei seltsame Argumente übergeben haben.

Ihr zweites Beispiel trennt die Argumente korrekt, aber wie Eddie Kelley vorgeschlagen hat, muss eines an der Vorderseite eingefügt werden. Es teilt boinccmd mit, dass Sie es als "--host" aufgerufen und dann weitere sechs Argumente übergeben haben. boinccmd kann die letzten fünf als zwei Optionen erkennen, hat aber keine Ahnung, worum es bei dem „localhost“-Geschäft geht. Soweit boinccmd das beurteilen kann, wurde es vom Terminal als aufgerufen

/Library/Application\ Support/BOINC\ Data/boinccmd localhost --passwd gobbledygook --project http://setiathome.berkeley.edu/ update

(beachten Sie das fehlende "--host").

boinccmd ist wahrscheinlich eines der allermeisten Programme, die sich nicht darum kümmern, was ihr erstes Argument ist, also könnten Sie wahrscheinlich einfach <string>HELLO</string>an den Anfang des ProgramArgumentsArrays schieben, aber es ist wahrscheinlich sauberer, den Schlüssel ganz zu entfernen Programund einfach dies zu verwenden:

<key>ProgramArguments</key>
    <array>
        <string>/Library/Application Support/BOINC Data/boinccmd</string>
        <string>--host</string>
        <string>localhost</string>
        <string>--passwd</string>
        <string>gobbledygook</string>
        <string>--project</string>
        <string>http://setiathome.berkeley.edu/</string>
        <string>update</string>
    </array>

Es mag wie eine bedeutungslose Redundanz erscheinen, aber einige Programme nutzen dies mit gutem Effekt: bash et al. fungieren als Login-Shells, wenn ihr erstes Argument mit beginnt -, & Vim tritt in verschiedene Emulationsmodi ein, wenn sein erstes Argument edoder vianstelle von ist vim.

Du hast gepostet, während ich meinen Hauptpost bearbeitet habe! Das ist eine großartige Erklärung. Danke dir.
Ich helfe gerne :)
@SirPavlova, tolle Hilfe! Gibt es jedoch ein Tool, mit dem eine Person den Konsolenaufruf in das Plist-Format konvertieren kann?

Basierend auf der Manpage für exec(3) scheint es, dass das erste Programmargument der Pfad zur ausführbaren Datei sein sollte:

The execv(), execvp(), and execvP() functions provide an array of pointers to null-terminated strings
 that represent the argument list available to the new program.  The first argument, by convention,
 should point to the file name associated with the file being executed. The array of pointers must be
 terminated by a NULL pointer.

Wenn Sie den Pfad zur ausführbaren Datei als Argument bei Index 0 angeben können, kann dies hilfreich sein ...

Wie ich den Beitrag bearbeitet habe, um zu zeigen, dass der boinccmd gefunden und ausgeführt wird, werden die ihm übergebenen Optionen irgendwie verstümmelt. Es sei denn, ich vermisse, was du sagst.
@Woodgie Ja, das wurde im Programm gefunden - Ihre ProgramArguments sind falsch, es wird der Pfadname der ausführbaren Datei benötigt
Oh. OH! Ich glaube, ich sehe jetzt. Warte mal, lass mich das testen.
BINGO, das zu tun und jeden Teil jedes Befehls in einen eigenen <string></string>-Container zu stecken, hat funktioniert. Danke dir. Ich habe dir gesagt, es war einfach!