bash - script de shell de Linux: ejecuta múltiples comandos en segundo plano y no finaliza incluso si el script finaliza

CorePress2024-01-24  8

Tengo script.sh, así que quiero ejecutarlo a través de la terminal (./script.sh)

Si ejecuto script.sh entonces debería iniciar algún otro comando (ffmpeg en este caso) según algunas condiciones

Funciona de esta manera, pero el problema es: si detengo/elimino script.sh, entonces ffmpeg también se elimina/detiene

Creo que los comandos ffmpeg u otros comandos no necesitan depender de script.sh, incluso si lo cierro, deberían ejecutarse

#!/bin/bash
while xxxxxxx; do 

startFFMPEG() { 
    nohup $(/root/bin/ffmpeg -i "url" -i "/var/www/logo/logo.png" outputcmd -y "1.m3u8"  </dev/null >/dev/null 2>&1 ||     /root/bin/ffmpeg -i "url" -i "/var/www/logo/logo.png" outputcmd -y "2.m3u8"  </dev/null >/dev/null 2>&1 ||     /root/bin/ffmpeg -i "url" -i "/var/www/logo/logo.png" outputcmd -y "3.m3u8"  </dev/null >/dev/null 2>&1  ) >/dev/null 2>&1 &
}
    echo "RUN COMMAND1" 
    startFFMPEG &


startFFMPEG() { 
        nohup $(/root/bin/ffmpeg -i "url2" -i "/var/www/logo/logo.png" outputcmd -y "11.m3u8"  </dev/null >/dev/null 2>&1 ||     /root/bin/ffmpeg -i "url2" -i "/var/www/logo/logo.png" outputcmd -y "12.m3u8"  </dev/null >/dev/null 2>&1 ||     /root/bin/ffmpeg -i "url3" -i "/var/www/logo/logo.png" outputcmd -y "13.m3u8"  </dev/null >/dev/null 2>&1  ) >/dev/null 2>&1 &
}
    echo "RUN COMMAND 2" 
    startFFMPEG &


sleep 10
done

¿Qué puedo hacer para solucionar este problema para que ffmpeg se ejecute incluso si se elimina el script?

1

Nohup $(...)??? ¿Qué?¿No crees que esas líneas lo hacen?

-oguz ismail

27/03/2021 a las 17:59

¿Por qué desea finalizar el script si desea que los comandos continúen ejecutándose? Su script es el programa principal que inicia otros problemas, por lo que cuando lo elimina, no continuará iniciando otros nuevos. Toda esa duplicación hace que me duelan los ojos.

- Allan Wind

27/03/2021 a las 18:01

Si por algún motivo se elimina script.sh (por ejemplo, actualizo el código en script.sh y luego lo vuelvo a ejecutar), en este caso se eliminan todos los comandos de ffmpeg

- wuqn yqow

27/03/2021 a las 18:03

aquí simplemente simplifiqué el script porque tiene muchos comandos, pero esta es la lógica. Solo necesito una forma en que el script ejecute el comando ffmpeg e incluso si se elimina, los comandos ffmpeg continuarán ejecutándose

- wuqn yqow

27/03/2021 a las 18:05

En su lugar, envíe una señal al script y haga que salga correctamente cuando esté a punto de repetirse. Si desea que finalice más rápido, mantenga el estado de escritura del script en el que se encuentra actualmente y luego, la próxima vez que lo inicie, calcule el último estado y continúe ejecutándolo desde allí.

- Allan Wind

27/03/2021 a las 18:06



------------------------------------

No hay ninguna razón para usar nohup aquí, ninguna en absoluto.

nohup sólo hace cuatro cosas:

Redirigir stdin desde /dev/null (si es anteriorprocedente de un TTY) Redirigir la salida estándar a nohup.out (si anteriormente fue a un TTTY) Redirigir stderr a nohup.out (si previamente fue a un TTY) Ignore cualquier señal HUP ("colgar") recibida. (El shell ya ignora los HUP de forma predeterminada en scripts no interactivos, e incluso en un intérprete interactivo, se puede usar disown -h para forzar el comportamiento).

Esas cosas son todo lo que necesitas para asegurarte de que una terminal cerrada no lleve consigo procesos secundarios con el mismo nivel de eficacia que proporciona nohup. (Si desea proteger contra Ctrl+c, puede solicitar además setsid o un manejo claro de SIGINT).

Puedes hacer todo esto tú mismo. La mayor parte ya lo estabas haciendo tú mismo.

#!/bin/bash

trap : HUP # Tell the shell not to do anything when it gets a HUP

startFFMPEG() {
    trap '' INT  # ignore SIGINT
    for ((i=0; i<3; i++)); do
      /root/bin/ffmpeg \
        -i "url" \
        -i "/var/www/logo/logo.png" \
        outputcmd \
        -y "$((i+1)).m3u8" \
        </dev/null >/dev/null 2>&1 \
        && return
    done
}

while xxxxxxx; do 
    echo "RUN COMMAND1" 
    startFFMPEG &

    echo "RUN COMMAND 2" 
    startFFMPEG &

    sleep 10
done

7

Bienvenido. Aunque todavía no estoy seguro de qué está intentando hacer OP

-oguz ismail

27/03/2021 a las 18:59

La operación no dice qué se entiende por "detener/matar" pero la señal predeterminada para matar es SIGTERM. Según tengo entendido, Op quiere que el script muera pero que los subprocesos continúen ejecutándose. No estoy seguro de que la trampa te dé ese comportamiento.

& ndash;Allan viento

27/03/2021 a las 19:02

@AllanWind, el shell no hace todo lo posible para finalizar trabajos que inició mientras se estaba cerrando. Los subprocesos mueren porque su salida estándar desaparece y obtienen un SIGPIPE, o su TTY desaparece y obtienen un SIGWINCH, o todo su grupo de control obtiene un SIGINT en el caso de Ctrl+c.

- Charles Duffy

27/03/2021 a las 19:54

@AllanWind, ...entonces, si el shell principal obtiene un SIGTERM, no es necesario cambiar nada para permitir que los hijos vivan, a menos que suceda algo más al mismo tiempo (como que el terminal se apague o que se inicie un proceso). en una sustitución de comando, por lo que su salida estándar es para un FIFO que lee el shell, lo que provoca un SIGPIPE después de que ese shell muere) lo que hace que uno de los otros mecanismos se vuelva relevante.

- Charles Duffy

27/03/2021 a las 19:56

Hay 20 comandos que deberían ejecutarse de forma independiente, por lo que si no uso nohup, necesito esperarlos uno por uno, porque nunca pasa al segundo si el primero todavía se está ejecutando

- wuqn yqow

27/03/2021 a las 20:31



------------------------------------

Cuando matas (3posix) el proceso principal (script.sh), obviamente dejará de ejecutar nuevos comandos. Cualquier proceso secundario como el subshell $() y los procesos ffmpeg continuarán ejecutándose.

Sin embargo, si interrumpes el proceso principal con Ctrl-c, SIGINT se envía al grupo de procesos, lo que tambiénfinalizar los subprocesos. La forma de solucionarlo es ejecutar sus subprocesos en una nueva sesión con setsid:

setsid /root/bin/ffmpeg -i "url" ... &

Como señala @CharlesDuffy, los niños normalmente obtendrían un SIGPIPE cuando intentan escribir en la tubería conectada al padre. En este caso, han sido redirigidos a /dev/null para que no se produzcan escrituras.

5

$() no necesariamente seguirá ejecutándose: el final de lectura de su salida estándar es un FIFO mantenido por el shell principal, por lo que las escrituras activarán un SIGPIPE.

– Charles Duffy

27/03/2021 a las 18:47

Los está redirigiendo a /dev/null.

- Allan Wind

27/03/2021 a las 18:48

De hecho, es seguro en el caso específico del OP, pero no en el caso general. Las personas que lean esta respuesta no siempre sabrán qué contexto es importante para determinar cuándoOtras declaraciones que contiene la respuesta también se aplican a su código y casos de uso, por lo que es útil explicarlas detalladamente.

- Charles Duffy

27/03/2021 a las 18:49

@CharlesDuffy actualizó la respuesta con tus comentarios. Avísame si me equivoqué o podría ser más claro.

- Allan Wind

27/03/2021 a las 18:53

La actualización me parece buena. Y actualicé mi respuesta para agregar una advertencia sobre cómo cambiar el grupo de sesión puede ser relevante si uno necesita poder sobrevivir a Ctrl+c, y no solo a la salida del terminal.

- Charles Duffy

27/03/2021 a las 18:54



------------------------------------

Puedes utilizar software de pantalla.

En ubuntu, instálalo:

sudo apt uopdate
sudo apt install screen

Luego, inicie la pantalla en una terminal:

screen

Para regresar a tu última pantalla

screen -r

Más información en este enlace

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare