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по умолчанию выводит fzfв stdout, а подстановка параметров просто запускает command ( fzf), полученную в результате вывода.

Одно из отличий между сценарием bashи zshсценарием заключается в том, что bashон дополнительно выводит выходные данные, $(__fzfcmd)а zshпросто захватывает их внутри массива. Я предполагаю, что из-за проблемы, zshкогда вы продолжаете fzfнаправлять вывод, куда вы не можете ввести, fzfа процесс, по которому fzfпередается, не получает никакого стандартного ввода. Ваш единственный выбор - ^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 -содержимое редактора не выводится на стандартный вывод, как это 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использование процесса подстановки.

dosentmatter
источник
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 работают из-за перенаправления вывода.

eyoung100
источник