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 $subshellno funcionará como$subshellno es un elemento secundario del proceso que está ejecutandowaitin. De todos modos, no esperaría el proceso haciendowaitasí que no importa mucho.kill $subshellva a eliminar la subcapa pero nosleepsi el subshell hubiera logrado iniciarlo en el momentokillfue corrido. Sin embargo, podría ejecutarsleepen 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?