zsh не може ввести термінал, коли трубопроводити stdin та stdout зі змінною командою, яка має вихід tty


11

Інформація про систему:

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)

Прокрутіть до ПРИКЛАДІ внизу, якщо ви просто хочете викопати спрощені приклади, які я зробив.

ПРИМІТКА. Я не великий zshкористувач.


Я дивився на fzfклавіші для bashі zsh.

Зверніть увагу , як вони обидва працюють зі змінною командою $(__fzfcmd). __fzfcmdза замовчуванням виводить fzfstdout, а підміна параметра просто виконує команду ( fzf), отриману в результаті виводу.

Одна з різниць між і bashі zshскриптом полягає в тому, що bashтой надалі передає вихід, $(__fzfcmd)але zshпросто захоплює його всередині масиву. Моя здогадка, це через проблему, zshколи ви надалі передаєте висновок, fzfкуди ви не можете ввести, fzfі процес, до якого перебуває труба, fzfне отримує жодного stdin. Ваш єдиний вибір - це ^Zчи ^C. ^CЗдається, чомусь передує процес. А може, вони просто хотіли його в масиві, щоб вони могли працювати zle vi-fetch-historyна ньому . bashВерсія робить деякі магії в ключі зв'язування з"\e^": history-expand-line

Тепер fzfце не важливо. Здається, що вам просто потрібна програма, яка виводить на те, ttyщоб викликати підстановку параметрів, щоб викликати цю проблему. Тому я покажу кілька простіших прикладів.

Ось декілька інших команд, які виводять на те, ttyщо може спричинити цю проблему в zsh:

  • vipe (запустіть редактор посеред труби)
  • 'vim -' (зробіть читати vim з stdin. подібний до vipe, але не виводить у stdout)

У наведених нижче прикладах замінити кожне входження vipeз , vim -якщо ви не хочете , щоб зробити окрему установку. Пам'ятайте лише, що vim -вміст редактора не буде виводити в stdout, як vipeце робиться

ПРИКЛАДИ:

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

Зараз мені в основному цікаво, чому 2)виникає проблема, zshале не для, bashі чому, 4)і 5)вирішує проблему zsh.

Вимоги, zshщоб мати цю проблему, здавалося б, саме те, що я виклав у назві:

  • вхідна труба
  • команда виконується за допомогою підстановки змінної / параметрів, яка має ttyвихід
  • вихідна труба

ОНОВЛЕННЯ

Я додав ще один обхідний шлях , який не викликає , zshщоб мати цю проблему, 5). Це схоже на, 4)але замість того, щоб перенаправляти stdoutбезпосередньо в stin, я перенаправляю його у файл, який перенаправляє на stdinвикористання процесу заміни.


1
Як psвам підкаже висновок , ні в одному з цих випадків раковини не застигають і не застрягають. Вони просто чекають дитячих процесів у звичайному порядку; і вони дійсно повернуться до запиту на введення нормальним способом, як тільки ці дочірні процеси будуть призупинені або припинені. Назва та тіло питання містять неявну помилкову передумову. "Чому моя оболонка замерзає?" - це невідповідне завантажене питання, коли ваша оболонка фактично не замерзає. У вас буде краще питання про видалення цієї неявної помилкової передумови.
JdeBP

Гаразд, я можу це змінити. Це насправді не заморожено в тому сенсі, що процес більше не може виконувати інструкції на процесорі. Ви вірні, що це просто чекає. Але хіба це не «застрягло»? Він чекає введення, я не в змозі його надати. Який кращий термін описати це стисло? Хіба це не відповідає цьому опису на схилі when either a computer program or system ceases to respond to inputs
dosentmatter

1
Оболонка не чекає введення. Він чекає своїх дітей. Це питання краще поставити просто описом того, що відбувається . Не формуйте гіпотези та умовиводи, такі як "моя оболонка заморожена", а потім не запитуйте про умовиводи. Опишіть, що відбувається, і запитайте про це: Послідовності введення спеціальних символьних терміналів (які, як правило, призупиняють завдання переднього плану, або переривають або виходять із завдання, або надсилають індикацію EOF на зчитування процесу з терміналу) не впливають. Що відбувається? Чому? . Це, до речі, копіюється на Debian Linux та FreeBSD / TrueOS,
JdeBP

1
Я повідомив про помилку в списку розсилки zsh для розробки . Наразі ви зможете обійти його, загорнувши його в (echo | $(echo vipe) | cat)
нижню частину

1
Те, що заміна процесу розпочинається у фоновому режимі, є задокументованим, я думаю (або, принаймні, відомим)
Стефан Шазелас

Відповіді:


0

Я вважаю, що ваше питання зводиться до неправильного цитування ваших розширень.

Цитування з zsh: 14 Розширення

Команда, вкладена в круглі дужки, передує знаку долара, як-от $(...)або цитується з наголосними наголосами, як-от " ...", замінюється на її стандартний вихід, при цьому всі видалені останні рядки видаляються. Якщо підміна не вкладається у подвійні лапки, вихід розбивається на слова за допомогою параметра IFS. Заміна $(cat foo)може бути замінена рівнозначною, але швидшою $(<foo). У будь-якому випадку, якщо встановлено параметр GLOB_SUBST, вихід підходить для створення імені файлу.

Зауважте, що приклад №2 у вашому запитанні призводить до нескінченного відлуння NULL через:

Якщо підміна не вкладається у подвійні лапки, вихід розбивається на слова за допомогою параметра IFS.

Іншими словами, оболонка нескінченно чекає echo, оскільки роздільник за замовчуванням - SPACE, відлуння ніколи не завершується. Див. TLDP: Внутрішні змінні . Це залишає підвішену трубу для catкоманди.

Я вважаю, що 4 і 5 працюють завдяки перенаправленню виводу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.