2012-04-20 9 views
9

Estoy intentando escribir una secuencia de comandos shell de Linux (preferiblemente bash), supuestamente nombrado detach.sh, para separar con seguridad los programas desde un terminal, tal que:sobre cómo escribir un script de shell de Linux para separar con seguridad los programas desde un terminal

  1. Invocación: ./detach.sh prog [arg1 arg2 ...].

  2. Es exec -able, p. Ej. mediante la ejecución de esto en su shell:

    exec ./detach.sh prog [arg1 arg2 ...] 
    
  3. Con citando adecuado (principalmente manejo de argumentos que contienen espacios en blanco).

  4. Descarta las salidas (ya que no son necesarias).

  5. No usa screen, tmux, etc. (misma razón con 4, más sin necesidad de un proceso de niñera extra).

  6. Usa comandos (razonablemente) portátiles y programas, y nada como start-stop-daemon que es bastante específico de la distribución.

he pensado en varias formas (líneas shebang #!/bin/bash olvidadas en aras de la brevedad):

  1. nohup:

    nohup "[email protected]" >& /dev/null & 
    
  2. disown:

    "[email protected]" >& /dev/null & 
    disown 
    
  3. setsid:

    setsid "[email protected]" >& /dev/null & 
    
  4. Usando una subcapa:

    ("[email protected]" >& /dev/null &) 
    
  5. nohup/setsid combinarse con subcapa:

    # Or alternatively: 
    # (nohup "[email protected]" >& /dev/null &) 
    (setsid "[email protected]" >& /dev/null &) 
    

Al utilizar gedit como el programa de prueba (sustituyendo la parte "[email protected]"), condición 1 se puede satisfacer con todos los métodos anteriores, pero la condición 2 se puede satisfacer con ninguno.

Sin embargo, si un programa arbitrario (pero no una orden interna del shell) son añadidas a la escritura 5, todas las condiciones parecen estar satisfecho (al menos para mí en el caso gedit). Por ejemplo:

(setsid "[email protected]" >& /dev/null &) 
# Not just `true' because it is also a shell builtin. 
/bin/true 

Cualquier persona con una idea acerca de una explicación de los fenómenos anteriores y cómo implementar correctamente los requisitos?

EDIT:

Con la condición 2, quiero decir que el programa debe ser separado de la terminal, pero corre como siempre lo contrario. Por ejemplo, con el caso gedit, la condición falla si gedit simplemente sale inmediatamente después de que el proceso del script ha finalizado.

+2

¿De qué manera solución al 5 no cumple con el requisito 2, suponiendo que tiene el tinglado ? O, aproximadamente de manera equivalente, ¿qué significa el requisito 2 que la solución 5 no lo satisface? –

+0

¿Qué espera que suceda cuando 'gedit' se ejecute en segundo plano? Dado que 'gedit' es un editor que se ejecuta de forma interactiva, pero un proceso en segundo plano es, más o menos por definición, algo que se ejecuta sin interacción del usuario, tal vez el problema es su elección de programa de prueba. Manejar programas basados ​​en X11 es bastante diferente de manejar compiladores y similares. ¿Qué ves que sucede cuando ejecutas 'gedit' en segundo plano? –

+0

Perdón por la explicación incorrecta de mi idea. Quise decir "separar" cuando decía "fondo". Por favor vea la versión actualizada de esta pregunta. Gracias por su ayuda :) –

Respuesta

3

Tras una investigación más profunda, se dieron a conocer estos hechos previamente inadvertidas:

  1. Ambos guiones 3 y 5 (la variante setsid solamente) se satisfacer todas las condiciones si un /bin/true se adjunta a la secuencia de comandos.

  2. Estas secuencias de comandos, tal como se modifica en el hecho 1, también funcionarán si /bin/true se reemplaza por for i in {0..9999}; do :; done.

Por lo tanto, podemos concluir que:

  • (De hecho, 1)

    niveles múltiples de desprendimiento (como en la escritura 5) es innecesaria, y la clave es el uso de la utilidad correcta (setsid).

  • (De hecho, 2)

    es necesaria para el éxito de la escritura de un retardo adecuado antes de la salida de bash. (Llamando programa externo /bin/true consume algo de tiempo, al igual que el tiempo puro-fiesta de los consumidores for i in {0..9999}; do :; done.)

    no he mirado el código fuente, pero supongo que una posible explicación es que fiesta puede salir antes de setsid acabados configurando el entorno de ejecución del programa a ejecutar, si no se aplica un retraso apropiado.

Y, por último, una solución óptima debe ser

#!/bin/bash 
setsid "[email protected]" >& /dev/null & 
sleep 0.01 

EDIT 1:

La necesidad de un retraso ha sido explicada here. Muchas gracias a @wilx!

EDIT 2:

(Gracias a @MateiDavid) parece que hemos olvidado para redirigir la entrada estándar, y una mejor manera sería:

#!/bin/bash 
setsid "[email protected]" >& /dev/null < /dev/null & 
+0

Intente omitir el fondo y la demora: 'setsid" $ @ "> & - 2> & - <& -'. –

+0

@MateiDavid: ¡Muchas gracias! He actualizado mi respuesta, pero el fondo todavía parece necesario para bash. –

0

Está intentando crear un proceso de demonio UNIX (es decir, un proceso que no tiene un terminal de control y que es su propio líder session). El comando setsid debe hacer esto por usted, pero usted es responsable de cerrar todos los descriptores de archivo que están abiertos en la terminal que está abandonando. Esto se puede hacer redirigiéndolos a /dev/null o usando la sintaxis del shell para cerrar los descriptores de archivos (por ejemplo, 2>&- y 0<&- en Bash).

+0

Gracias, pero creo que los guiones 3 y 5 (ver mi pregunta) han hecho esto, mientras que todavía no resuelven el problema. Además, la causa del fenómeno de que una llamada a '/ bin/true' resuelve el problema sigue sin explicarse. –

1

creo que hay que hacer setsid "[email protected]" >& /dev/null & wait para que la terminal de control no desaparezca antes de setsid se las arregla para bifurcar al niño.

ACTUALIZACIÓN

Me parece que esto funciona tanto en la línea de comandos y como argumento de -c:

(setsid tail -F /var/log/messages >& /dev/null) & disown 
+0

Muchas gracias :) He actualizado mi propia respuesta para reflejar su sugerencia. –

+1

La explicación es muy razonable.Pero 'bash -c 'setsid sleep 1> &/dev/null & wait'' de alguna manera bloquea (mientras que no bloquea en' bash' interactivo), por lo que no resuelve el problema por el momento. –

+0

@ CasperTi.Vector: He actualizado mi respuesta. – wilx

Cuestiones relacionadas