zsh nie może wprowadzać danych do terminala podczas przesyłania strumieniowego stdin i stdout za pomocą zmiennej komendy, która ma wyjście tty

11

Informacja o systemie:

macOS Sierra 10.12.6
zsh 5.4.2 (x86_64-apple-darwin16.7.0)
GNU bash, version 4.4.12(1)-release (x86_64-apple-darwin16.3.0)

Przewiń do PRZYKŁADÓW u dołu, jeśli chcesz po prostu zagłębić się w uproszczone przykłady, które stworzyłem.

UWAGA: Nie jestem dużym zshużytkownikiem.


Szukałem na fzfskróty klawiszowe dla bashi zsh.

Zwróć uwagę, jak oba uruchamiają zmienne polecenie $(__fzfcmd). __fzfcmddomyślnie wyświetla fzfwyjście na standardowe wyjście, a podstawienie parametru po prostu uruchamia polecenie ( fzf) wynikające z wyjścia.

Jedną różnicą między skryptem bashi zshjest to, że ta bashkolejna potokuje wyjście, $(__fzfcmd)ale zshtylko przechwytuje je w tablicy. Domyślam się, że jest to spowodowane problemem, zshkiedy dalej potokujesz wyjście fzftam, gdzie nie możesz wejść, fzfa proces przekazywany do fzfnie dostaje żadnego standardowego wejścia. Twoim jedynym wyborem jest ^Zlub ^C. ^Cz jakiegoś powodu wydaje się stanowić tło procesu. A może po prostu chcieli go w tablicy, aby mogli na nim biegaćzle vi-fetch-history . bashWersja robi jakaś magia w kluczu wiązania z"\e^": history-expand-line

Teraz fzfnie jest ważne. Wygląda na to, że potrzebujesz tylko programu, który wyświetla polecenie ttywywołania przez podstawienie parametru, aby spowodować ten problem. Pokażę więc kilka prostszych przykładów.

Oto kilka innych poleceń wysyłanych do tych, ttyktóre mogą powodować ten problem zsh:

  • vipe (uruchom edytor na środku potoku)
  • 'vim -' (spraw, aby vim czytał ze standardowego wejścia. podobny do vipe, ale nie wyświetli na standardowe wyjście)

W poniższych przykładach zastąpić wszystkie wystąpienia vipeze vim -jeśli nie chcesz zrobić oddzielny zainstalować. Pamiętaj tylko, że vim -nie wypisze zawartości edytora na standardowe wyjście, tak jak viperobi.

PRZYKŁADY:

1) echo 1 | vipe | cat            # works in both bash and zsh
2) echo 1 | $(echo vipe) | cat    # works in bash only. zsh problem with no output until I hit `^C`:
   ^C
   zsh: done                    echo 1 | 
   zsh: suspended (tty output)  $(echo vipe) | 
   zsh: interrupt               cat
   # seems like the process is backgrounded. I can still see it in jobs command

3) cat <(echo 1 | $(echo vipe))   # zsh and bash has the problem. I'm guessing because
                                  # the file isn't finished writing and cat is
                                  # blocking vipe's tty output
                                  # both their `^C` output is just:
   ^C # nothing special, as expected

4) cat < <(echo 1 | $(echo vipe)) # works in both bash and zsh
5) echo 1 | $(echo vipe) > >(cat) # works in both bash and zsh

# The following don't have and input pipe to vipe.
# Type something then send EOF with ^D
6) vipe | cat                     # works for both
7) $(echo vipe) | cat             # works for both

Teraz głównie zastanawiam się, dlaczego 2)ma problem z, zshale nie z powodu, bashi dlaczego 4)i 5)rozwiązuje problem zsh.

Wymagania, zshaby ten problem wydawał się być dokładnie tym, co podałem w tytule:

  • rura wejściowa
  • polecenie uruchamiane przez podstawienie zmiennej / parametru, które ma ttydane wyjściowe
  • rura wyjściowa

AKTUALIZACJA

I dodaje inny obejście, które nie powoduje zshmieć tego problemu 5). Jest podobny do, 4)ale zamiast przekierowywać stdoutbezpośrednio do stin, przekierowuję go do pliku, który przekierowuje na stdinstosowanie substytucji procesu.

dosentmatter
źródło
1
Jak wynika z danych wyjściowych ps, w żadnym z tych przypadków pociski nie są zamrożone lub zablokowane. Po prostu czekają na procesy potomne w normalny sposób; i rzeczywiście powrócą do monitowania o wprowadzenie danych w normalny sposób, gdy te procesy potomne zostaną zawieszone lub zakończone. Tytuł i treść pytania zawierają domyślną fałszywą przesłankę. „Dlaczego moja skorupa się zawiesza?” to pytanie, na które nie można odpowiedzieć, gdy twoja skorupa w ogóle się nie zawiesza. Lepiej byłoby usunąć to ukryte fałszywe założenie.
JdeBP,
Ok, mogę to zmienić. Nie jest tak naprawdę zawieszony w tym sensie, że proces nie jest już w stanie uruchomić instrukcji na CPU. Masz rację, że to tylko czeka. Ale czy to nie „utknęło”? Czeka na dane wejściowe, których nie jestem w stanie podać. Jaki jest lepszy termin na zwięzłe opisanie tego? Nie zgadza się z tym opisem zawieszenia when either a computer program or system ceases to respond to inputs
dosentmatter
1
Powłoka nie czeka na dane wejściowe. Czeka na swoje dzieci. To pytanie lepiej byłoby po prostu opisać, co się stanie . Nie twórz hipotez i wniosków, takich jak „moja skorupa jest zamrożona”, a następnie nie pytaj o wnioski. Opisz, co się dzieje i zapytaj o to: sekwencje wejściowe terminala specjalnego (które normalnie zawiesiłyby zadanie na pierwszym planie, przerwały lub zakończyły zadanie, lub wysłały wskazanie EOF do odczytu procesu z terminala) nie mają wpływu. Co się dzieje? Dlaczego? . Nawiasem mówiąc, można to powielać w systemach Debian Linux i FreeBSD / TrueOS,
JdeBP,
1
Mam zgłosił błąd na liście dyskusyjnej zsh rozwój . Na razie powinieneś być w stanie obejść to, owijając ją w podpowłokę(echo | $(echo vipe) | cat)
Stéphane Chazelas
1
Wydaje mi się, że fakt, że podstawianie procesów rozpoczyna się w tle, jest przynajmniej
udokumentowany

Odpowiedzi:

0

Uważam, że Twój problem sprowadza się do niewłaściwego cytowania rozszerzeń.

Cytowanie z zsh: 14 Expansion

Polecenie zawarte w nawiasach poprzedzone znakiem dolara $(...), lub cytowane poważnymi akcentami, takimi jak „ ...”, jest zastępowane standardowym wyjściem, a wszelkie końcowe znaki nowej linii są usuwane. Jeśli podstawienie nie jest ujęte w podwójne cudzysłowy, dane wyjściowe są dzielone na słowa przy użyciu parametru IFS. Podstawienie $(cat foo)może zostać zastąpione równoważnym, ale szybszym $(<foo). W obu przypadkach, jeśli ustawiona jest opcja GLOB_SUBST, dane wyjściowe kwalifikują się do wygenerowania nazwy pliku.

Zauważ, że przykład 2 w twoim pytaniu powoduje nieskończone echo wartości NULL z powodu:

Jeśli podstawienie nie jest ujęte w podwójne cudzysłowy, dane wyjściowe są dzielone na słowa przy użyciu parametru IFS.

Innymi słowy, powłoka nieskończenie czeka na echo, ponieważ domyślnym ogranicznikiem jest SPACJA, echo nigdy się nie kończy. Zobacz TLDP: Zmienne wewnętrzne . To pozostawia zawieszoną rurę dla catpolecenia.

Jako przeczucie, uważam, że 4 i 5 działają z powodu przekierowania wyjścia.

eyoung100
źródło