次のコマンドについて考えてみます。
_seq 5 | grep $(tail -n1) <(seq 9)
_
zsh
で実行する場合1:
_tail: error reading 'standard input': Input/output error
_
bash
で同じように実行すると、次のように出力されます。
_5
_
OK。コメントで説明されているように、コマンド置換$(tail -n1)
はその親からstdin
を継承します。しかし、なぜそれがzsh
で起こらないのですか?
これはzsh
のみのものですか、それとも他のシェルも行うことですか?どこに文書化されていますか?
ここで、_zsh -c
_を介して同じコマンドを実行すると、次のようになります。
_zsh -c 'seq 5 | grep $(tail -n1) <(seq 9)'
_
同じエラーメッセージを出力する代わりに、_tail -n1
_の後に停止し、ユーザー入力を待つので、入力すると
_19
2
4
_
次にヒット Ctrl+D、印刷します
_4
_
何が起きてる ?
1:これは、重要な場合、zsh
のarchlinux
_5.3.1
_を使用します。
bash
/ksh
にあることに気付くでしょう
_echo foo | echo "$(cat)"
_
foo
を出力しますが、
_<<< foo echo "$(cat)"
_
そうではありません。
最初のケースでは、$(cat)
は子プロセスで展開され、そのstdinがパイプからリダイレクトされた後、最終的にecho
を実行します。
2番目のケースでは、リダイレクトの前に$(cat)
が展開されます。
パイプとリダイレクトは別のものです。パイプには、いくつかのリダイレクトが含まれますが、コマンドを並行して開始することも含まれます。これは、各パイプコンポーネント内のリダイレクトの前の早い段階で発生します。
zsh
で
_$ sleep 1 | ps -jfH $(ps -fH >&2)
UID PID PPID C STIME TTY TIME CMD
chazelas 2495 2494 0 20:59 pts/1 00:00:00 /bin/zsh
chazelas 31201 2495 0 21:20 pts/1 00:00:00 sleep 1
chazelas 31202 2495 0 21:20 pts/1 00:00:00 ps -fH
UID PID PPID PGID SID C STIME TTY TIME CMD
chazelas 2495 2494 2495 2495 0 20:59 pts/1 00:00:00 /bin/zsh
chazelas 31201 2495 31201 2495 0 21:20 pts/1 00:00:00 sleep 1
chazelas 31203 2495 31201 2495 0 21:20 pts/1 00:00:00 ps -jfH
_
今回は、コマンド置換が親シェルによって拡張されていることに気付くでしょう。
覚えておくべきことの1つは、zsh
では、特に_mult_ios
_オプション(デフォルトで有効)に関しては、パイプがリダイレクトのように扱われることです。
あなたがするとき:
_echo foo > file | tr o e
_
foo
はfile
とtr
の両方に移動します。
に:
_uname | cat < /etc/issue
_
cat
には、uname
の出力と_/etc/issue
_のコンテンツの両方が供給されます。したがって、zsh
では、_<
_/_>
_とパイプからのリダイレクトは同じ段階で発生する必要があります。できれば拡張後。
いずれにせよ、あなたはいつでもすることができます:
_echo foo | { echo "$(cat)"; }
_
zsh
とbash
/ksh
の両方で、いつでもできるように:
_{ echo "$(cat)"; } <<< foo
_
bash
とzsh
の両方で。
の原因について:
_tail: error reading 'standard input': Input/output error
_
エラー。対話型シェルでは、コマンド置換は親で行われるため、ターミナルのフォアグラウンドプロセスグループでは行われません。
tail
は、親シェルのプロセスグループで実行されます。そのシェルがセッションリーダーである場合、それは 孤立したプロセスグループ になるため、tail
がttyデバイスから読み取ろうとすると、EIOで失敗します。
zsh
がセッションリーダーではなかった場合。たとえば、別のシェルからzsh
を開始した場合、プロセスグループはSIGTTINを受け取ります。メインのシェルプロセスはそれを無視しますが、tail
は最終的に中断されます。