
答え1
シェルの子プロセスとして、ls
シェルのオープンファイル記述子を継承します。標準ファイル記述子(stdin、stdout、stderr(または0、1、2))は擬似端末に接続され、端末エミュレータによって処理されます。
たとえば(Linuxシステムの場合):
$ ls /proc/$$/fd -l
total 0
lrwx------ 1 muru muru 64 Dec 10 16:15 0 -> /dev/pts/3
lrwx------ 1 muru muru 64 Dec 10 16:15 1 -> /dev/pts/3
lrwx------ 1 muru muru 64 Dec 10 16:15 2 -> /dev/pts/3
lrwx------ 1 muru muru 64 Dec 10 16:15 255 -> /dev/pts/3
$ ls /proc/$(pgrep terminator -f)/fd -l | grep pts/3
lrwx------ 1 muru muru 64 Dec 10 16:15 26 -> /dev/pts/3
つまり、 の出力ls
またはシェル自体はシェルで処理されず、端末エミュレータ (GNOME 端末、ターミネータ、xterm など) で処理されます。
これをテストできます。
pts
Linuxでは、GNOME端末などの端末エミュレータで使用される擬似端末()を見つけます。
$ ls -l /proc/$(pgrep -n gnome-terminal)/fd | grep pts
lrwx------ 1 muru muru 64 Dec 10 18:00 1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Dec 10 18:00 15 -> /dev/pts/20
lrwx------ 1 muru muru 64 Dec 10 18:00 2 -> /dev/pts/1
これで、非標準fd(0、1、2以外のfd)を使用してgnome-terminal
シェルに入出力を提供します。端末エミュレータは、このPTSに送信されたデータを読み取り、画面に表示します(色など一部の処理)。この場合は15
に接続してくださいpts/20
。これまで何かを書くと、この端末に表示されると予想できます。
追加資料:
別の場合に私がすることは次のとおりです。
echo $(ls)
a=$(date)
vim `command -v some_script`
~と呼ばれるコマンドの置き換え。コマンドの置き換えでは、コマンドの出力はシェル自体によってキャプチャされ、印刷しない限り(たとえばecho $(ls)
)端末に到達しません。イベントは以下で処理されました。ホクラキンの答え。
答え2
私は質問を命令置換の意味で誤解したことがわかりました。この場合にのみ、シェルは出力処理に参加します。
これも興味を引き起こすことができることを願っています...
strace -p 2140
このllを実行する前にecho $(/bin/echo foo)
シェルに接続してください。これは結果の一部です。
pipe([3, 4])
pipe([5, 6])
...
read(3, "foo\n", 128)
子プロセスでは、次のことが発生します。
dup2(4, 1)
close(4)
close(3)
...
execve("/bin/echo", ...
シェルはファイル記述子 3 と 4 を連結して分岐します。子プロセスは、stdout
新しいプログラムを実行する前にfdを4に設定します。したがって、子プロセスによって作成されたすべての内容は、stdout
fd 3の親シェルから読み取ることができます。