Sì, bashcome in ksh(da dove proviene la funzione), i processi all'interno della sostituzione del processo non sono attesi (prima di eseguire il comando successivo nello script).
per <(...)uno, di solito va bene come in:
cmd1 <(cmd2)
la shell attenderà cmd1e cmd1in genere attenderà in cmd2virtù della sua lettura fino alla fine del file sulla pipe che viene sostituita e tale fine del file si verifica in genere quando cmd2muore. Questa è la stessa ragione per diverse shell (non bash) non si preoccupano in attesa di cmd2in cmd2 | cmd1.
Per cmd1 >(cmd2), tuttavia, che non è generalmente il caso, come è più cmd2che tipicamente attende cmd1lì così sarà generalmente uscita dopo.
Ciò è stato risolto in zshquello che attende cmd2lì (ma non se lo scrivi come cmd1 > >(cmd2)e cmd1non è incorporato, usa {cmd1} > >(cmd2)invece come documentato ).
kshnon aspetta per impostazione predefinita, ma ti consente di aspettarlo con il waitbuilt-in (rende anche disponibile il pid $!, anche se ciò non aiuta se lo fai cmd1 >(cmd2) >(cmd3))
rc(con la cmd1 >{cmd2}sintassi), come kshse fosse possibile ottenere i pid di tutti i processi in background $apids.
es(anche con cmd1 >{cmd2}) attende cmd2like in zshe attende anche reindirizzamenti cmd2in <{cmd2}corso.
bashrende disponibile il pid di cmd2(o più esattamente della subshell mentre viene eseguito cmd2in un processo figlio di quella subshell anche se è l'ultimo comando lì) disponibile $!, ma non ti fa aspettare.
Se è necessario utilizzare bash, è possibile aggirare il problema utilizzando un comando che attenderà entrambi i comandi con:
{ { cmd1 >(cmd2); } 3>&1 >&4 4>&- | cat; } 4>&1
Ciò rende entrambi cmd1e cmd2hanno il loro fd 3 aperto a una pipe. catattenderà per la fine del file all'altra estremità, così sarà in genere solo uscire quando entrambi cmd1e cmd2sono morti. E la shell attenderà quel catcomando. Potresti vederlo come una rete per catturare la terminazione di tutti i processi in background (puoi usarlo per altre cose iniziate in background come con &, coprocs o anche comandi che in background stessi a condizione che non chiudano tutti i loro descrittori di file come fanno normalmente i demoni ).
Nota che grazie a quel processo di subshell sprecato menzionato sopra, funziona anche se cmd2chiude il suo fd 3 (i comandi di solito non lo fanno, ma alcuni lo fanno sudoo lo sshfanno). Le versioni future di bashpotrebbero eventualmente fare l'ottimizzazione lì come in altre shell. Quindi avresti bisogno di qualcosa come:
{ { cmd1 >(sudo cmd2; exit); } 3>&1 >&4 4>&- | cat; } 4>&1
Per assicurarsi che ci sia ancora un ulteriore processo di shell con quel fd 3 aperto in attesa di quel sudocomando.
Nota che catnon leggerà nulla (poiché i processi non scrivono sul loro fd 3). È lì solo per la sincronizzazione. Farà solo una read()chiamata di sistema che tornerà senza nulla alla fine.
Puoi effettivamente evitare l'esecuzione catutilizzando una sostituzione di comando per eseguire la sincronizzazione della pipe:
{ unused=$( { cmd1 >(cmd2); } 3>&1 >&4 4>&-); } 4>&1
Questa volta, è la shell invece catche sta leggendo dalla pipe la cui altra estremità è aperta su fd 3 di cmd1e cmd2. Stiamo utilizzando un'assegnazione variabile per cui lo stato di uscita di cmd1è disponibile in $?.
Oppure potresti fare manualmente la sostituzione del processo, e quindi potresti anche usare il tuo sistema in shquanto diventerebbe la sintassi della shell standard:
{ cmd1 /dev/fd/3 3>&1 >&4 4>&- | cmd2 4>&-; } 4>&1
tuttavia, come notato in precedenza, non tutte le shimplementazioni che aspetterebbero cmd1dopo il cmd2completamento (anche se è meglio del contrario). Quella volta, $?contiene lo stato di uscita di cmd2; sebbene bashe zshrendere lo cmd1stato di uscita disponibile in ${PIPESTATUS[0]}e $pipestatus[1]rispettivamente (vedere anche l' pipefailopzione in alcune shell in modo da $?poter segnalare il fallimento dei componenti del tubo diversi dall'ultimo)
Si noti che yashha problemi simili con la sua funzione di reindirizzamento del processo . cmd1 >(cmd2)sarebbe scritto cmd1 /dev/fd/3 3>(cmd2)lì. Ma cmd2non è atteso e non puoi nemmeno usarlo waite il suo pid non è reso disponibile $!nemmeno nella variabile. Useresti lo stesso lavoro come per bash.