¿Por qué la función no volverá hasta que finalice el proceso en segundo plano?

21

Considera este script:

#!/bin/bash
function start {
  leafpad &
  echo $!
}
PID=$(start)
echo "PID is $PID"

El script no continúa más allá de su llave de cierre hasta que finaliza el proceso del bloc de notas, aunque sea un proceso en segundo plano.

¿Por qué es esto? ¿Es posible iniciar un proceso en segundo plano desde una función?

usuario234565
fuente

Respuestas:

22

La función regresa, pero la sustitución del comando se bloquea, porque creó un trabajo en segundo plano, pero aún tiene su stdout fd abierta. Solo ciérrelo agregando >/dev/nullantes de &.

#!/bin/bash
function start {
  leafpad >/dev/null &
  echo $!
}
PID=$(start)
echo "PID is $PID"

Si desea que su proceso también tenga stdin, stdout, stderr cerrados, use esto:

leafpad >/dev/null 0>&1 2>&1 &

Esto cerrará stdin (0), stdout (1) y stderr (2), luego el fondo (&). Además, cuando use estas redirecciones de flujo , no olvide que están "engañadas", lo que significa que están duplicadas en el orden de ejecución.

1>/dev/null 2>&1

y

2>&1 1>/dev/null

no son lo mismo ! En el primero, está duplicando una secuencia a / dev / null (que es lo que desea), en el segundo, está duplicando / dev / stdout a stderr, y luego, cerrando stdout. Por lo tanto, cualquier mensaje enviado a stderraparecerá en su consola.

Adrien M.
fuente
Confirmado en mi sistema
usuario120161
10
No estás cerrando las transmisiones, las estás redirigiendo.
dcat
44
cerrar; n>&-donde nestá el descriptor de archivo.
dcat
1
@dcat: Sí, pero la redirección hacia / desde /dev/nullno generará errores de E / S cuando un proceso intente escribir su stdout, pero descubra que 1es un FD no válido. Entonces, la terminología en la publicación es incorrecta, no la programación real de bash. (En realidad, duplicar FD 1 a 0 significa que stdin será un descriptor de archivo abierto O_RDONLY, lo que probablemente dará un error (en lugar de los no bytes deseados disponibles) cuando el proceso intente leer). Ej. wc >/dev/null 0>&1->wc: standard input: Bad file descriptor
Peter Cordes
1
@PeterCordes: cerrar el descriptor antiguo y redirigir el nuevo no tiene por qué ser mutuamente excluyente. exec <&- >&- <>/dev/null >&0maneja stdin / out bastante exhaustivamente. Hace una diferencia en zshal menos qué tipo de concatenación de todas las aperturas en el mismo descriptor automáticamente cuando se establece multios.
mikeserv