Quiero implementar algo como este Q/A pero para un sub-shell. Aquí hay un ejemplo mínimo de lo que estoy intentando:
(subshell=$BASHPID
(kill $subshell & wait $subshell 2>/dev/null) &
sleep 600)
echo subshell done
¿Cómo puedo hacer que solo subshell done
? devuelve en lugar de:
./test.sh: line 4: 5439 Terminated ( subshell=$BASHPID; ( kill $subshell && wait $subshell 2> /dev/null ) & sleep 600 )
subshell done
Editar:puede que me equivoque con la terminología aquí, por subcapa me refiero al proceso dentro del primer paréntesis.
Actualización:
Quiero publicar el fragmento del programa real para el contexto, arriba hay una simplificación:
# If subshell below if killed or returns error connected variable won't be set
(if [ -n "$2" ];then
# code to setup wpa configurations here
# If wifi key is wrong kill subshell
subshell=$BASHPID
(sudo stdbuf -o0 wpa_supplicant -Dwext -i$wifi -c/etc/wpa_supplicant/wpa_supplicant.conf 2>&1 \
| grep -m 1 "pre-shared key may be incorrect" \
&& kill -s PIPE "$subshell") &
# More code which does the setup necessary for wifi
) && connected=true
# later json will be returned based on if connected is set
Respuesta aceptada:
Nota:
wait $subshell
no funcionará como$subshell
no es un elemento secundario del proceso que está ejecutandowait
in. De todos modos, no esperaría el proceso haciendowait
así que no importa mucho.kill $subshell
va a eliminar la subcapa pero nosleep
si el subshell hubiera logrado iniciarlo en el momentokill
fue corrido. Sin embargo, podría ejecutarsleep
en el mismo proceso conexec
- puede usar SIGPIPE en lugar de SIGTERM para evitar el mensaje
- dejar una variable sin comillas en contextos de lista tiene un significado muy especial en
bash
.
Habiendo dicho todo eso, puedes hacer:
(
subshell=$BASHPID
kill -s PIPE "$subshell" &
sleep 600
)
echo subshell done
(reemplace sleep 60
con exec sleep 60
si quieres el kill
matar sleep
y no solo el subshell, que en este caso podría no tener tiempo para ejecutar sleep
para cuando lo mates).
En cualquier caso, no estoy seguro de lo que quieres lograr con eso.
sleep 600 &
sería una forma más confiable de iniciar sleep
en segundo plano si eso es lo que querías hacer (o (sleep 600 &)
si quisieras ocultar ese sleep
proceso desde el shell principal)
Ahora con tu
realsudo stdbuf -o0 wpa_supplicant -Dwext -i"$wifi" -c/etc/wpa_supplicant/wpa_supplicant.conf
comando, tenga en cuenta que sudo
genera un proceso secundario para ejecutar el comando (aunque solo sea porque puede necesitar registrar su estado o realizar algunas tareas de sesión PAM después). stdbuf
sin embargo, ejecutará wpa_supplicant
en el mismo proceso, por lo que al final tendrás tres procesos (además del resto del script) en wpa_supplicant
ascendencia:
- la subcapa
- sudo como un niño de 1
- wpa_supplicant (que antes ejecutaba stdbuf) como hijo de 2
Si matas a 1, eso no mata automáticamente a 2. Sin embargo, si matas a 2, a menos que sea con una señal como SIGKILL que no puede ser interceptada, eso matará a 3 como sudo
pasa a reenviar las señales que recibe al comando que ejecuta.
En cualquier caso, esa no es la subcapa que querrías eliminar aquí, son 3 o al menos 2.
Ahora, si se está ejecutando como root
y el resto del script no lo es, no podrás matarlo tan fácilmente.
Necesitarías el kill
para hacerse como root
, entonces necesitarías:
sudo WIFI="$wifi" bash -c '
(echo "$BASHPID" &&
exec stdbuf -o0 wpa_supplicant -Dwext -i"$WIFI" -c/etc/wpa_supplicant/wpa_supplicant.conf 2>&1
) | {
read pid &&
grep -m1 "pre-shared key may be incorrect" &&
kill -s PIPE "$pid"
}'
De esa forma, wpa_supplicant
se ejecutará en el mismo $BASHPID
proceso como el subshell como lo estamos haciendo con exec
.
Obtenemos el pid a través de la tubería y ejecutamos kill
como raíz.
Tenga en cuenta que si está listo para esperar un poco más,
sudo stdbuf -o0 wpa_supplicant -Dwext -i"$wifi" -c/etc/wpa_supplicant/wpa_supplicant.conf 2>&1 |
grep -m1 "pre-shared key may be incorrect"
Tendría wpa_supplicant
eliminado automáticamente con un SIGPIPE (por el sistema, por lo que no hay problema de permisos) la próxima vez escribe algo en esa tubería después de grep
se ha ido.
Algunas implementaciones de shell no esperarían sudo
después de grep
ha regresado (dejándolo ejecutándose en segundo plano hasta que obtiene SIGPIPEd), y con bash
, también puede hacerlo usando grep ... <(sudo ...)
sintaxis, donde bash
no espera sudo
ya sea después de grep
ha regresado.
¿Más en Grep lento para salir después de encontrar una coincidencia?