使用具有tty输出的可变命令对stdin和stdout进行配管时,zsh无法输入到终端


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按键绑定的bashzsh

注意它们都是如何运行可变命令的$(__fzfcmd)__fzfcmd默认情况下,输出fzf到stdout,并且参数替换仅运行fzf由输出产生的命令()。

bashzsh脚本之间的区别是,bash另一个脚本通过管道传递输出,$(__fzfcmd)zsh仅将其捕获到数组中。我的猜测是由于一个问题,zsh当您进一步通过管道传输fzf无法输入的位置的输出时,fzf通过管道传输到的过程fzf不会得到任何标准输入。您唯一的选择是to ^Z^C^C由于某种原因,似乎使该过程成为背景。或者,也许他们只是想以阵列的形式使用它们,以便可以在其上运行zle vi-fetch-history。该bash版本在与"\e^": history-expand-line

现在fzf并不重要。似乎您只需要一个输出到的程序tty就可以通过参数替换来调用该程序,从而导致此问题。因此,我将显示一些更简单的示例。

这是一些其他输出到的命令,这些命令tty可能会导致以下问题zsh

  • vipe(在管道中间运行编辑器)
  • 'vim -' (使vim从stdin读取。类似于vipe,但不会输出到stdout)

在下面的例子中,更换的每次出现vipevim -,如果你不想做一个单独的安装。只是要记住,vim -不会像vipe那样将编辑器内容输出到stdout 。

例子:

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

好的,我可以更改它。从进程不再能够在CPU上运行指令的意义上来说,它并没有真正冻结。您是正确的,它只是在等待。但这不是“卡住”吗?它正在等待我无法提供的输入。简要描述这个词的更好的词是什么?它与hang的 描述不符when either a computer program or system ceases to respond to inputs

1
外壳程序不等待输入。它正在等待孩子。这个问题最好是简单描述发生的事情。不要形成假设和推论,例如“我的外壳被冻结”,然后再询问推论。描述发生的情况并询问:特殊字符终端输入序列(通常会挂起前台作业,中断或退出该作业或向从终端读取的进程发送EOF指示)无效。怎么了?为什么?。顺便说一下,这可以在Debian Linux和FreeBSD / TrueOS上复制
JdeBP

1
我已经在zsh开发邮件列表中报告了该错误。现在,你应该能够解决它在一个子shell包装它(echo | $(echo vipe) | cat)
斯特凡Chazelas

1
这一过程取代均在后台启动的事实证明,我认为(或至少知道)
斯特凡Chazelas

Answers:


0

我相信您的问题归结为不正确地引用您的扩展。

引用zsh:14扩展

括号内的命令前面带有一个美元符号(如 $(...)或),并带有重音符号(如“ ...”),其命令将替换为其标准输出,并删除所有尾随的换行符。如果替换没有用双引号引起来,则使用IFS参数将输出分成单词。$(cat foo)可以用等效的替代方法来代替,但是速度更快$(<foo)。在任何一种情况下,如果设置了选项GLOB_SUBST,则输出符合生成文件名的条件。

请注意,由于以下原因,您的问题中的示例2导致无限回显NULL:

如果替换没有用双引号引起来,则使用IFS参数将输出分成单词。

换句话说,shell无限期地等待echo,因为默认定界符为SPACE,所以回声永远不会完成。 请参阅TLDP:内部变量。这为cat命令留下了一个悬挂的管道。

作为一种预感,我相信4和5可以通过输出重定向来工作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.