Sí, al bash
igual 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 cmd1
y cmd1
típicamente estará esperando en cmd2
virtud de leer hasta el final del archivo en la tubería que se sustituye, y ese final del archivo generalmente ocurre cuando cmd2
muere. Esa es la misma razón varios proyectiles (no bash
) no se molestan en espera de cmd2
en cmd2 | cmd1
.
Para cmd1 >(cmd2)
, sin embargo, eso no es generalmente el caso, ya que es más cmd2
que normalmente espera a que cmd1
no lo hará por lo general después de la salida.
Eso se solucionó en las zsh
esperas cmd2
allí (pero no si lo escribe como cmd1 > >(cmd2)
y cmd1
no está integrado, use {cmd1} > >(cmd2)
en su lugar como se documenta ).
ksh
no espera de forma predeterminada, pero le permite esperar con el wait
incorporado (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, ksh
excepto que puede obtener los pids de todos los procesos en segundo plano $apids
.
es
(también con cmd1 >{cmd2}
) espera cmd2
como en zsh
, y también espera redirecciones cmd2
en <{cmd2}
proceso.
bash
hace que el pid de cmd2
(o más exactamente de la subshell ya que se ejecuta cmd2
en 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 cmd1
y cmd2
tener su fd 3 abierta a una tubería. cat
esperará al final de su archivo en el otro extremo, por lo general sólo se salga cuando ambos cmd1
y cmd2
están muertos. Y el shell esperará ese cat
comando. 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 cmd2
cierra su fd 3 (los comandos generalmente no hacen eso, pero a algunos les gusta sudo
o lo ssh
hacen). Las versiones futuras de bash
eventualmente 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 sudo
comando.
Tenga en cuenta que cat
no 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 cat
utilizando 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 cat
que está leyendo desde la tubería cuyo otro extremo está abierto en fd 3 de cmd1
y cmd2
. Estamos utilizando una asignación variable para que el estado de salida de cmd1
esté disponible en $?
.
O podría hacer la sustitución del proceso a mano, y luego incluso podría usar el sistema, sh
ya 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 sh
implementaciones esperarían cmd1
después de que cmd2
haya terminado (aunque eso es mejor que al revés). Ese tiempo, $?
contiene el estado de salida de cmd2
; sin embargo, bash
y zsh
hacer que cmd1
el estado de salida esté disponible en ${PIPESTATUS[0]}
y $pipestatus[1]
respectivamente (consulte también la pipefail
opció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 yash
tiene problemas similares con su función de redirección de procesos . cmd1 >(cmd2)
Sería escrito cmd1 /dev/fd/3 3>(cmd2)
allí. Pero cmd2
no se espera y tampoco se puede usar wait
para esperarlo, y su pid tampoco está disponible en la $!
variable. Usarías las mismas soluciones alternativas que para bash
.