Tuyau semi-asynchrone

11

Supposons que j'ai le tuyau suivant:

a | b | c | d

Comment puis-je attendre la fin de c(ou b) dans shou bash? Cela signifie que le script dpeut démarrer à tout moment (et n'a pas besoin d'être attendu) mais nécessite une sortie complète de cpour fonctionner correctement.

Le cas d'utilisation est un difftoolpour gitqui compare les images. Il est appelé par gitet doit traiter son entrée (la a | b | cpartie) et afficher les résultats de la comparaison (la dpartie). L'appelant supprimera l'entrée requise pour aet b. Cela signifie qu'avant de revenir du script, le processus c(ou b) doit se terminer. D'un autre côté, je ne peux pas attendre dcar cela signifie que j'attends la saisie de l'utilisateur.

Je sais que je peux écrire les résultats de cdans un fichier temporaire, ou peut-être utiliser un FIFO dans bash. (Je ne sais pas si le FIFO va aider, cependant.) Est-il possible d'y parvenir sans fichiers temporaires sh?

ÉDITER

Il serait peut-être suffisant que je puisse trouver l'ID de processus du c(ou b) processus de manière fiable. Ensuite, le tube entier pourrait être démarré de manière asynchrone et je pouvais attendre un ID de processus. Quelque chose dans le sens de

wait $(a | b | { c & [print PID of c] ; } | d)

MODIFIER ^ 2

J'ai trouvé une solution, les commentaires (ou encore meilleures solutions) sont les bienvenus.

krlmlr
la source
Vous voulez dire que vous voulez dcommencer cla sortie du traitement uniquement après la cfin? Vous ne voulez dpas commencer à traiter chaque ligne de sortie au fur et à mesure?
terdon
@terdon: Non, dest libre de commencer quand bon lui semble, mais cdoit se terminer avant que je puisse continuer.
krlmlr
Cela semble contradictoire, si vous dpouvez commencer quand vous le souhaitez, qu'attendez-vous exactement?
terdon
@terdon: développé pour montrer le cas d'utilisation.
krlmlr
Si dn'utilise pas la sortie de calors il ne semble pas logique de faire dpartie du pipeline. Mais si dutilise l'entrée, il dfaut travailler un moment sur son entrée après l'avoir lue pour que votre approche fasse la différence.
Hauke ​​Laging du

Réponses:

6
a | b | { c; [notify];} | d

La notification peut être effectuée par exemple par un signal à un PID qui a été passé dans une variable d'environnement ( kill -USR1 $EXTPID) ou en créant un fichier ( touch /path/to/file).

Une autre idée:

Vous exécutez le processus suivant (celui que vous souhaitez démarrer) à partir du pipeline:

a | b | { c; exec >&-; nextprocess;} | d

ou

a | b | { c; exec >&-; nextprocess &} | d
Hauke ​​Laging
la source
Merci. Mais ensuite, la création d'un fichier temporaire pour la sortie intermédiaire est plus détaillée et plus facile à analyser (pour un humain). De plus, comment puis-je éviter les conditions de course avec le signal? ... J'espérais une solution plus propre, mais si c'est la voie à suivre, alors tant pis.
krlmlr le
@krlmlr Quelle condition de concurrence?
Hauke ​​Laging du
notifypourrait être exécuté avant de configurer le piège de signal. Comment puis-je m'assurer de ne pas manquer ce signal?
krlmlr
@krlmlr Vous arrêtez le script qui appelle le pipeline jusqu'à ce qu'il reçoive lui-même un signal qui est envoyé après que le trapa été défini.
Hauke ​​Laging du
Votre montage: le tuyau est appelé dans une boucle, sur laquelle je n'ai aucun contrôle. Malheureusement, { c; bg; }ou { c; exit 0; }ne semble pas fonctionner.
krlmlr
5

Si je comprends bien votre question, cela devrait fonctionner:

a | b | c | { (exec <&3 3<&-; d) &} 3<&0

(l'astuce fd 3 est parce que certains (la plupart) des shells redirigent stdin vers / dev / null avec &).

Stéphane Chazelas
la source
4

En bash, vous pouvez utiliser une substitution de processus . La commande dans la substitution de processus s'exécute de manière asynchrone, elle n'est pas attendue.

a | b | c > >(d)
Gilles 'SO- arrête d'être méchant'
la source
Merci. C'est bashseulement, non - pas de shsupport?
krlmlr
@krlmlr Bash / zsh uniquement (et ksh93 avec quelques modifications).
Gilles 'SO- arrête d'être méchant'
3

C'est ce que j'ai trouvé par essais et erreurs, avec l'aide de la contribution de Hauke:

a | b | { c; kill -PIPE $$; } | d

De manière équivalente:

a | b | ( c; kill -PIPE $$; ) | d

(Ce dernier est plus explicite, car {}s'exécutera de toute façon dans un sous-shell si à l'intérieur d'un tuyau.)

D'autres signaux (y compris QUIT, TERMet USR1) le travail aussi, mais dans ce cas , la description du signal est affiché sur le terminal.

Je me demande si c'est l'intention originale du PIPEsignal. Selon le manuel :

SIGPIPE: Le PIPEsignal est envoyé à un processus lorsqu'il tente d'écrire sur un tuyau sans qu'un processus soit connecté à l'autre extrémité.

Cela signifie que lorsque j'envoie artificiellement un signal de tuyau au sous-shell, il se termine silencieusement, laissant le consommateur final ( d) seul.

Cela fonctionne à la fois dans shet bash.

krlmlr
la source
0

Vous pouvez utiliser le spongeprogramme du package "moreutils":

a | b | c | sponge | d

l'éponge sera pour la fin de cla sortie avant de la canaliser d. J'espère que c'est ce que tu voulais.

Minijackson
la source
0

Vous pouvez simplement faire:

a | b | c | (d ; cat > /dev/null)

Ainsi, une fois dterminé, le catabsorbera le reste de cla production jusqu'à ce qu'il se termine.

D'accord. Après les commentaires, je pense que la réponse est de commencer directement den arrière-plan.

Faire:

a | b | c | (d &)

ou utilisez la solution de Stéphane Chazelas en cas de problème de dlecture depuis stdin .

angus
la source
Je crains que mon cas d'utilisation soit plutôt l'inverse: ctermine plus tôt que d, et je dois attendre jusqu'à la cfin, mais je m'en fiche d.
krlmlr
Désolé, je ne comprends pas. Que voulez-vous faire une fois cterminé et den cours d'exécution? Tuer d?
angus
dpossède une interface graphique et peut s'exécuter jusqu'à ce que l'utilisateur la ferme.
krlmlr
OK ... mais cela se produit déjà. Quand a, bet cfinissant leur travail, ils ferment la sortie standard et sortent; et ne dreste en cours d'exécution. Voulez-vous envoyer dà l'arrière-plan une fois cterminé? Est-ce que c'est ça?
angus
Oui, ddoit être envoyé à l'arrière-plan une fois cterminé.
krlmlr le