Wird gestartet, um Programmargumente korrekt zu lesen

18

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 mich über eine missbräuchliche Verwendung beschwert.

Der spezifische Fehler, den ich erhalte, ist der Verwendungstext des Befehls, der in das Systemprotokoll geschrieben wird. Daraus schließe ich, dass die anderen Informationen (Pfad zum Befehl, Timing usw.) in der Liste 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

Das heißt aber nur "Ich bin mit einem Fehler ausgegangen".

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

Nun, ich habe execvp (3) gelesen und bin nicht der Klügere, also frage ich Sie sehr gerne.

Wenn Sie den Befehl vom Terminal aus ausführen, sieht er normalerweise so aus:

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

Das ist ein Genuss.

Und so habe ich es in den 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 den Datensatz hatte ich ursprünglich den Pfad zu boinccmd \ escaped, aber das funktioniert nicht, launchd entgeht 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 das schien auch nicht zu funktionieren.

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

Vielen Dank.


ANTWORTEN:

Die erste Zeile von ProgramArguments muss der Pfad zum Programm sein. Dies ist, was mich auslöste und was wahrscheinlich mit dem Kommentar "... Bitte sehr sorgfältig lesen! .." gemeint war. Wenn ich das alles an Ort und Stelle hatte, wirkt das Ganze wie ein Zauber. Vielen Dank.

<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 letzte Änderung, die für eine leicht verständliche Erklärung, WARUM dies sein sollte, zu sagen ist, finden Sie in SirPavlovas Erklärung.

~ W

Woodgie
quelle
Unter Verwendung von launchctl list com.label.plist kann ich sehen, dass launchd die richtigen Teile des Befehls zum Zusammenfügen bekommt. Ich dachte, vielleicht war es ein Problem im Zusammenhang mit der -, aber anscheinend nicht.
Woodgie
1
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 wird nur in Leerzeichen aufgeteilt, bevor die Argumente an das ausgeführte Programm übergeben werden. Es kann auch hilfreich sein, wenn Sie den genauen Fehler anzeigen, der boinccmdgemeldet wird.
Kevin Reid
Habe meinen Beitrag bearbeitet, um zu sagen, was ich sehe. Nicht, dass es hilfreich wäre! Außerdem erhalte ich den gleichen Fehler, wenn ich die Optionen in ihrem Whitespace aufteile. Ich vermute, es ist das - das verursacht das Problem irgendwie.
Woodgie
1
Ich würde versuchen, nur Program oder ProgramArguments zu verwenden, nicht beide
user151019 18.11.13

Antworten:

19

Der ProgramSchlüssel gibt die Datei an, die ausgeführt werden soll, und der ProgramArgumentsSchlüssel gibt die Argumente an, die an den ausführenden Prozess übergeben werden. Streng genommen können Sie einem Prozess beliebige Argumente übergeben. Die Konvention lautet jedoch, dass das erste Argument der Name sein sollte, unter dem der Prozess aufgerufen wurde, sodass die meisten Programme das erste Argument ignorieren. Die auszuführende Datei ist offensichtlich eine notwendige Information. Wenn jedoch der ProgramSchlüssel fehlt, gibt launchd aus ProgramArguments rein praktischen Gründen den gleichen Wert wie das erste Argument vor .

Ihr erstes Beispiel startet boinccmd und gibt Argumente an, die dem Befehl terminal entsprechen

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

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

Ihr zweites Beispiel trennt die Argumente korrekt, aber wie Eddie Kelley vorgeschlagen hat, muss eines vorne 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 "localhost" geht. Soweit boinccmd erkennen kann, wurde es vom Terminal aus 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, denen das erste Argument egal ist. Sie könnten also wahrscheinlich nur den Anfang <string>HELLO</string>des ProgramArgumentsArrays verschieben, aber es ist wahrscheinlich sauberer, den ProgramSchlüssel insgesamt zu entfernen und einfach Folgendes 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 kann wie eine bedeutungslose Redundanz erscheinen, aber einige Programme verwenden dies mit gutem Erfolg: bash et al. wirken als Login - Shells , wenn ihr erstes Argument mit beginnt -, und Vim tritt verschiedene Emulationsmodi , wenn das erste Argument ist edoder vistatt vim.

SirPavlova
quelle
1
Du hast gepostet, als ich meinen Hauptbeitrag bearbeitet habe! Dies ist eine großartige Erklärung. Vielen Dank.
Woodgie
1
Gerne helfen :)
SirPavlova
@ SirPavlova, große Hilfe! Gibt es jedoch ein Tool, mit dem die Person den Konsolenaufruf in das plist-Format konvertieren kann?
Gaussblurinc
6

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

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 ...

Eddie Kelley
quelle
Wie ich den zu zeigenden Beitrag bearbeitet habe, wird die Boinccmd gefunden und ausgeführt, und die Optionen, die an sie übergeben werden, werden irgendwie entstellt. Es sei denn, ich vermisse, was du sagst.
Woodgie
1
@Woodgie Ja, das wurde in Program gefunden - Ihr ProgramArguments ist falsch, es benötigt den Pfadnamen der ausführbaren Datei
user151019 18.11.13
Oh. OH! Ich glaube ich sehe jetzt. Warte, lass mich das testen.
Woodgie
BINGO, das zu tun und jeden Teil jedes Befehls in einen eigenen <string> </ string> -Container zu schreiben, hat funktioniert. Vielen Dank. Ich habe dir gesagt, es war einfach!
Woodgie