Rura półsynchroniczna


11

Załóżmy, że mam następującą potok:

a | b | c | d

Jak mogę czekać na zakończenie c(lub b) w shlub bash? Oznacza to, że skrypt dmoże się uruchomić w dowolnym momencie (i nie trzeba na niego czekać), ale cdo prawidłowego działania wymaga pełnego wyjścia .

Sprawa stosowanie jest difftooldla gitże porównuje obrazy. Jest wywoływany giti musi przetworzyć dane wejściowe ( a | b | cczęść) i wyświetlić wyniki porównania ( dczęść). Dzwoniący usunie dane wymagane dla ai b. Oznacza to, że przed powrotem ze skryptu proces c(lub b) musi zostać zakończony. Z drugiej strony nie mogę się doczekać, dponieważ oznacza to, że czekam na dane wejściowe użytkownika.

Wiem, że mogę zapisać wyniki cdo pliku tymczasowego lub użyć FIFO w bash. (Nie jestem jednak pewien, czy FIFO pomoże). Czy można to osiągnąć bez tymczasowych plików sh?

EDYTOWAĆ

Być może byłoby wystarczające, gdybym mógł w wiarygodny sposób znaleźć identyfikator procesu c(lub b) procesu. Wtedy cała rura mogłaby zostać uruchomiona asynchronicznie i mogłem poczekać na identyfikator procesu. Coś w stylu

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

EDYCJA ^ 2

Znalazłem rozwiązanie, komentarze (lub jeszcze lepsze rozwiązania) są mile widziane.


Masz na myśli, że chcesz drozpocząć przetwarzanie danych cwyjściowych dopiero po czakończeniu? Nie chcesz drozpoczynać przetwarzania każdej linii wyjściowej, jaka się pojawi?
terdon

@terdon: Nie, dmożna rozpocząć, kiedy tylko chce, ale cmusi się skończyć, zanim będę mógł przejść dalej.
krlmlr

To wydaje się być wewnętrznie sprzeczne, jeśli dmożna zacząć, kiedy chce, na co dokładnie czekasz?
terdon

@terdon: rozwinięty, aby pokazać przypadek użycia.
krlmlr

Jeśli dnie używa danych wyjściowych c, wydaje się, że nie ma sensu dwchodzić w skład potoku. Ale jeśli dkorzysta z danych wejściowych, to dpo ich przeczytaniu musi działać chwilę po ich przeczytaniu, aby Twoje podejście miało jakąkolwiek różnicę.
Hauke ​​Laging

Odpowiedzi:


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

Powiadomienia można dokonać np. Przez sygnał do PID, który został przekazany w zmiennej środowiskowej ( kill -USR1 $EXTPID) lub przez utworzenie pliku ( touch /path/to/file).

Inny pomysł:

Wykonujesz następny proces (ten, aby móc rozpocząć, na który czekasz) z potoku:

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

lub

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

Dzięki. Ale później utworzenie pliku tymczasowego dla wyniku pośredniego jest bardziej szczegółowe i łatwiejsze do przeanalizowania (dla człowieka). Ponadto, jak mogę uniknąć wyścigu z sygnałem? ... Miałem nadzieję na czystsze rozwiązanie, ale jeśli to jest właściwy sposób, niech tak będzie.
krlmlr

@krlmlr Jakie warunki wyścigu?
Hauke ​​Laging

notifymoże być wykonany zanim ustawię pułapkę sygnału. Jak mogę się upewnić, że nie przegapię tego sygnału?
krlmlr

@krlmlr Zatrzymujesz skrypt, który wywołuje potok, dopóki nie otrzyma samego sygnału, który jest wysyłany po trapzdefiniowaniu.
Hauke ​​Laging

Twoja edycja: Potok jest wywoływany w pętli, nad którą nie mam kontroli. Niestety { c; bg; }lub { c; exit 0; }nie działa.
krlmlr

5

Jeśli dobrze rozumiem twoje pytanie, powinno to działać:

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

(sztuczka fd 3 jest spowodowana tym, że niektóre (większość) powłok przekierowuje standardowe wejście na / dev / null za pomocą &).



3

Oto, co znalazłem metodą prób i błędów przy pomocy informacji Hauke:

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

Odpowiednio:

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

(To ostatnie jest bardziej wyraźne, ponieważ i tak {}będzie działać w podpowłoce, jeśli będzie w potoku).

Niektóre inne sygnały (włącznie QUIT, TERMi USR1) działają też jednak w tym przypadku opis sygnału jest wyświetlany na terminalu.

Zastanawiam się, czy taka jest pierwotna intencja PIPEsygnału. Zgodnie z instrukcją :

SIGPIPE: PIPESygnał jest wysyłany do procesu, gdy próbuje on zapisać do potoku bez procesu podłączonego do drugiego końca.

Oznacza to, że kiedy sztucznie wysyłam sygnał potoku do podpowłoki, po cichu kończy się, pozostawiając końcowego konsumenta ( d) samego.

Działa to zarówno shi bash.


0

Możesz użyć spongeprogramu z pakietu „moreutils”:

a | b | c | sponge | d

gąbka będzie na końcu cwyjścia przed podłączeniem do niego d. Mam nadzieję, że tego właśnie chciałeś.


0

Możesz po prostu zrobić:

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

Tak więc po dzakończeniu catabsorbuje resztę cmocy wyjściowej aż do jej zakończenia.

Ok. Po komentarzach myślę, że odpowiedź powinna rozpocząć się bezpośrednio dw tle.

Robić:

a | b | c | (d &)

lub skorzystaj z rozwiązania Stephane Chazelas , jeśli występują problemy z dczytaniem ze standardowego wejścia .


Obawiam się, że mój przypadek użycia jest odwrotny: ckończy się wcześniej niż d, i muszę czekać do końca, cale nie przejmuję się d.
krlmlr

Przepraszam, nie rozumiem Co chcesz zrobić, gdy cskończy się i dnadal działa? Zabić d?
angus

dma GUI i może działać, dopóki użytkownik go nie zamknie.
krlmlr

OK ... ale to już się dzieje. Kiedy a, bi czakończyć swoją pracę, oni blisko stdout i wyjść; i tylko ddziała. Czy chcesz wysłać ddo tła po czakończeniu? Czy to to?
angus

Tak, dpowinien zostać wysłany do tła po czakończeniu.
krlmlr
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.