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と、パイプされたプロセスがfzfstdinを取得できないという問題が発生したためです。あなたの唯一の選択は、^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直接リダイレクトする代わりに、プロセス置換stinstdin使用してリダイレクトするファイルにリダイレクトします。


1
の出力からpsわかるように、これらのいずれの場合も、シェルはフリーズまたはスタックしていません。彼らは単に通常の方法で子プロセスを待っています。そして、それらの子プロセスが一時停止または終了すると、通常の方法で入力を求めるプロンプトにループバックします。質問のタイトルと本文に暗黙の誤った前提が含まれています。「なぜシェルがフリーズするのですか?」シェルが最初に実際にフリーズしていない場合、答えのないロードされた質問です。この暗黙の誤った前提を取り除くためのより良い質問があるでしょう。
JdeBP

はい、変更できます。プロセスがCPUで命令を実行できなくなったという意味では、実際にはフリーズしていません。ただ待っているだけです。しかし、それは「スタック」していませんか?入力を待機していますが、提供できません。これを簡潔に説明するのに適した用語は何ですか?それは、この説明と一致しないこつを when either a computer program or system ceases to respond to inputs
dosentmatter

1
シェルは入力を待機していません。子供を待っています。この質問は、何が起こるか簡単に説明したほうがよいでしょう。「私の殻は凍っている」などの仮説や推論を行わずに、推論について質問してください。何が起こるかを説明し、それについて質問します。特殊文字の端末入力シーケンス(通常はフォアグラウンドジョブを中断するか、ジョブを中断または終了するか、端末から読み取るプロセスにEOF指示を送信します)は効果がありません。何が起こっている?どうして?。ちなみに、これはDebian LinuxとFreeBSD / TrueOSで複製可能です
JdeBP '19

1
zsh開発メーリングリストでバグを報告しました。今のところ、あなたはサブシェルでそれをラップすることにより、それを回避するにはことができるはず(echo | $(echo vipe) | cat)
ステファンChazelas

1
プロセス置換がバックグラウンドで起動しているという事実は、私が思うに文書(あるいは少なくとも知られる)
ステファンChazelasを

回答:


0

あなたの問題は、あなたの拡張を不適切に引用したことに端を発していると思います。

zsh:14拡張からの引用

のよう$(...)にドル記号が前に付いた括弧で囲まれたコマンド、または ' ...'のようにアクサングラーブで引用されたコマンド は、標準出力に置き換えられ、末尾の改行は削除されます。置換が二重引用符で囲まれていない場合、IFSパラメーターを使用して出力が単語に分割されます。置換$(cat foo)は、同等の高速なものに置き換えることができ$(<foo)ます。どちらの場合も、オプションGLOB_SUBSTが設定されている場合、出力はファイル名生成に適格です。

質問の例2では、​​次の理由によりNULLの無限エコーが発生することに注意してください。

置換が二重引用符で囲まれていない場合、IFSパラメーターを使用して出力が単語に分割されます。

つまり、シェルはを無限に待機しechoます。デフォルトの区切り文字はSPACEであるため、エコーは完了しません。 TLDP:内部変数を参照してください。これにより、catコマンド用のハングしたパイプが残ります。

直感的に、4と5は出力リダイレクトのために機能すると思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.