Sí, al bashigual que en ksh(de dónde proviene la característica), no se esperan los procesos dentro de la sustitución del proceso (antes de ejecutar el siguiente comando en el script).
para <(...)uno, eso generalmente está bien como en:
cmd1 <(cmd2)
el caparazón estará esperando cmd1y cmd1típicamente estará esperando en cmd2virtud de leer hasta el final del archivo en la tubería que se sustituye, y ese final del archivo generalmente ocurre cuando cmd2muere. Esa es la misma razón varios proyectiles (no bash) no se molestan en espera de cmd2en cmd2 | cmd1.
Para cmd1 >(cmd2), sin embargo, eso no es generalmente el caso, ya que es más cmd2que normalmente espera a que cmd1no lo hará por lo general después de la salida.
Eso se solucionó en las zshesperas cmd2allí (pero no si lo escribe como cmd1 > >(cmd2)y cmd1no está integrado, use {cmd1} > >(cmd2)en su lugar como se documenta ).
kshno espera de forma predeterminada, pero le permite esperar con el waitincorporado (también hace que el pid esté disponible $!, aunque eso no ayuda si lo hace cmd1 >(cmd2) >(cmd3))
rc(con la cmd1 >{cmd2}sintaxis), igual que, kshexcepto que puede obtener los pids de todos los procesos en segundo plano $apids.
es(también con cmd1 >{cmd2}) espera cmd2como en zsh, y también espera redirecciones cmd2en <{cmd2}proceso.
bashhace que el pid de cmd2(o más exactamente de la subshell ya que se ejecuta cmd2en un proceso secundario de esa subshell aunque sea el último comando allí) esté disponible $!, pero no te deja esperar.
Si tiene que usarlo bash, puede solucionar el problema utilizando un comando que esperará ambos comandos con:
{ { cmd1 >(cmd2); } 3>&1 >&4 4>&- | cat; } 4>&1
Eso hace que tanto cmd1y cmd2tener su fd 3 abierta a una tubería. catesperará al final de su archivo en el otro extremo, por lo general sólo se salga cuando ambos cmd1y cmd2están muertos. Y el shell esperará ese catcomando. Podrías verlo como una red para detectar la finalización de todos los procesos en segundo plano (puedes usarlo para otras cosas que se inician en segundo plano, como con &, coprocs o incluso comandos que se ejecutan en segundo plano, siempre que no cierren todos sus descriptores de archivos como suelen hacer los demonios )
Tenga en cuenta que gracias al proceso de subshell desperdiciado mencionado anteriormente, funciona incluso si cmd2cierra su fd 3 (los comandos generalmente no hacen eso, pero a algunos les gusta sudoo lo sshhacen). Las versiones futuras de basheventualmente pueden hacer la optimización allí como en otros shells. Entonces necesitarías algo como:
{ { cmd1 >(sudo cmd2; exit); } 3>&1 >&4 4>&- | cat; } 4>&1
Para asegurarse de que todavía hay un proceso de shell adicional con ese fd 3 abierto esperando ese sudocomando.
Tenga en cuenta que catno leerá nada (ya que los procesos no escriben en su fd 3). Solo está ahí para la sincronización. Solo hará una read()llamada al sistema que regresará sin nada al final.
En realidad, puede evitar la ejecución catutilizando una sustitución de comando para realizar la sincronización de la tubería:
{ unused=$( { cmd1 >(cmd2); } 3>&1 >&4 4>&-); } 4>&1
Esta vez, es el caparazón en lugar de lo catque está leyendo desde la tubería cuyo otro extremo está abierto en fd 3 de cmd1y cmd2. Estamos utilizando una asignación variable para que el estado de salida de cmd1esté disponible en $?.
O podría hacer la sustitución del proceso a mano, y luego incluso podría usar el sistema, shya que eso se convertiría en la sintaxis estándar de la shell:
{ cmd1 /dev/fd/3 3>&1 >&4 4>&- | cmd2 4>&-; } 4>&1
aunque tenga en cuenta, como se señaló anteriormente, que no todas las shimplementaciones esperarían cmd1después de que cmd2haya terminado (aunque eso es mejor que al revés). Ese tiempo, $?contiene el estado de salida de cmd2; sin embargo, bashy zshhacer que cmd1el estado de salida esté disponible en ${PIPESTATUS[0]}y $pipestatus[1]respectivamente (consulte también la pipefailopción en algunos shells para $?poder informar el fallo de los componentes de la tubería que no sean el último)
Tenga en cuenta que yashtiene problemas similares con su función de redirección de procesos . cmd1 >(cmd2)Sería escrito cmd1 /dev/fd/3 3>(cmd2)allí. Pero cmd2no se espera y tampoco se puede usar waitpara esperarlo, y su pid tampoco está disponible en la $!variable. Usarías las mismas soluciones alternativas que para bash.