Ejecutar un comando cada vez que Mac se inicia con launchctl/plist

Necesito ejecutar nohup nice synergys -f --config ~/bin/conf/synergy.conf &el comando cada vez que se inicia la computadora.

Como está escrito en esta publicación , se me ocurrió el siguiente código plist.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd >
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>synergy</string>
    <key>ProgramArguments</key>
    <array>
        <string>nohup nice /usr/bin/synergys -f --config /Users/USER/bin/conf/synergy.conf &</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>LaunchOnlyOnce</key>
    <true/>
</dict>
</plist>

Y, ejecutó este comando.

launchctl load ./synergy.plist 

Sin embargo, recibí este mensaje de error.

launchctl: no plist was returned for: ./synergy.plist
launchctl: no plist was returned for: ./synergy.plist
nothing found to load

¿Qué le pasa a mi lista? ¿O mi comando launchctrl está mal en las opciones?

Respuestas (1)

El problema inmediato es que su archivo .plist no tiene el formato correcto: el contenido <string>...</string>debe codificarse con entidades HTML, es decir, &debe codificarse como &amp;(nota: puede verificar el formato de los archivos .plist con plutil -lint filename.plist). Pero hay algunos otros cambios que deben hacerse...

Iniciar programas con launchd es bastante diferente a iniciarlos desde un shell. La mayor diferencia es que desde el shell, desea que el programa vaya al fondo y se ejecute independientemente del shell, por lo que lo envuelve en nohup ... &. Con launchd, en realidad es mejor que el programa permanezca en "primer plano" para que launchd pueda vigilarlo.

Además, los elementos de ProgramArguments no serán analizados por un shell, por lo que enumerar el comando y sus argumentos con espacios entre ellos no funciona; haga que cada argumento sea un elemento separado de la matriz.

Aquí está mi puñalada en una sinergia .plist. No he probado esto, por lo que es posible que necesite algunos ajustes para que funcione correctamente (vea las notas a continuación):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd >
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>local.synergy</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/synergys</string>
        <string>-f</string>
        <string>--config</string>
        <string>/Users/USER/bin/conf/synergy.conf</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>Nice</key>
    <integer>10</integer>
    <key>KeepAlive</key>
    <false/>
    <key>AbandonProcessGroup</key>
    <true/>
</dict>
</plist>

Las dos últimas claves anteriores se ocupan de cómo debería reaccionar launchd si/cuando el programa synergys sale. De forma predeterminada, elimina todos los subprocesos supervivientes y lanza una nueva instancia; estas dos teclas suprimen ambas partes, lo que puede o no ser lo que desea. Además, una cosa que esto no hace que su versión nohupsí hace es redirigir stdin y stdout a nohup.out (en caso de que la terminal desaparezca); en cambio, IIRC launchd registra las cosas que se les envían. Si synergys tiene el hábito de enviar resultados, es posible que desee agregar algo como esto a .plist:

    <key>StandardOutPath</key>
    <string>/dev/null</string>
    <key>StandardErrorPath</key>
    <string>/dev/null</string>

Además, como dijo mankoff, debe poner esto en ~/Library/LaunchAgents para que se cargue automáticamente cada vez que inicie sesión. Ah, y probablemente debería agregar un local.prefijo al nombre del archivo (como hice con la etiqueta) para cumplir a la convención de nomenclatura de DNS inverso.

Dios mío, gracias por esto: plutil -lint filename.plist
Gran consejo para el plutil, muy útil.
¿Para qué sirve la clave Nicey el entero 10?
Además, ¿hay alguna razón por la que no use <key>Program</key><string>/usr/bin/synergys</string>y luego pase el resto de los argumentos como <key>ProgramArguments</key><array><string>Argument_1</string><string>Argument_2</string></array>?
@hobbes3: el Nicevalor ejecuta el programa con prioridad reducida, equivalente al comando agradable en el original. La razón por la que no usé <key>Program</key>es la redundancia (y la pereza): tendrías que enumerar /usr/bin/synergyscomo el Program y también como el primer elemento de ProgramArguments.