次のコマンドを検討してください。
seq 5 | grep $(tail -n1) <(seq 9)
zsh
1で実行すると:
tail: error reading 'standard input': Input/output error
で同じタスクを実行すると、bash
次のように出力されます。
5
いいえコメントに記載されているように、コマンド置換は親エントリから継承さ$(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
5.3.1
on です。archlinux
答え1
あなたは知っているでしょうbash
/ksh
echo foo | echo "$(cat)"
出力foo
が
<<< foo echo "$(cat)"
いいえ。
最初のケースでは、標準入力はパイプからリダイレクトされ、最後に$(cat)
実行されるサブプロセスから解放されます。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)"; }
inzsh
とbash
/ksh
いつものように:
{ echo "$(cat)"; } <<< foo
そしてbash
。zsh
理由は次のとおりです。
tail: error reading 'standard input': Input/output error
間違い。対話型シェルでは、コマンド置換は親プロセスで実行されるため、端末のフォアグラウンドプロセスグループでは実行されません。
tail
親シェルのプロセスグループで実行されます。シェルがセッションリーダーの場合、孤児プロセスグループしたがって、tail
ttyデバイスから読み取ろうとすると、EIOが失敗します。
zsh
会議の主催者ではない場合。たとえば、別のシェルから起動すると、zsh
プロセスグループはSIGTTINを受け取ります。デフォルトのシェルプロセスはこれを無視しますが、tail
最終的に中断されます。