bash関数を使用してそれ自体に関するいくつかの情報をstderrにダンプし、それを呼び出してcat
パイプラインを形成する場合、パイプラインのどのステップが別のステップを呼び出すかをどうやって知ることができますか?
1つの解決策は、各ステップに、、、、、などの名前を付けることです。a
その後、出力を見るとわかります。しかし、ステップ名を指定したくないとしましょう。ステージのファイルディスクリプタを報告したステージが別のステージのファイルディスクリプタであることを確認して、前者が後者にパイプされていることを知る方法はありますか?では、共有パイプをどのように識別しますか?試してみましたが、チェーンの作り方がわかりません。b
c
d
a > b > c > d
stdout
stdin
lsof
例えば、
printf '%s\n' main "$(lsof -p $$ | grep dev)" > /dev/stderr
pipe() {
printf '%s %s:%s %s\n' $1 $BASHPID $BASH_SUBSHELL $$ > /dev/stderr
printf '%s\n' $1 "$(lsof -p $$ | grep dev)" > /dev/stderr
cat
}
echo
echo hi | pipe a | pipe b | pipe c | pipe d
生産
main
bash 51147 Setup 0u CHR 16,2 0t476770 3717 /dev/ttys002
bash 51147 Setup 1u CHR 16,2 0t476770 3717 /dev/ttys002
bash 51147 Setup 2u CHR 16,2 0t476770 3717 /dev/ttys002
bash 51147 Setup 26u CHR 15,0 0t214349 579 /dev/ptmx
bash 51147 Setup 27u CHR 15,1 0t1206500 579 /dev/ptmx
a 51176:1 51147
d 51147:0 51147
b 51177:1 51147
c 51179:1 51147
b
bash 51147 Setup 1u CHR 16,2 0t477304 3717 /dev/ttys002
bash 51147 Setup 2u CHR 16,2 0t477304 3717 /dev/ttys002
bash 51147 Setup 26u CHR 15,0 0t214349 579 /dev/ptmx
bash 51147 Setup 27u CHR 15,1 0t1206500 579 /dev/ptmx
bash 51147 Setup 254u CHR 16,2 0t477304 3717 /dev/ttys002
d
bash 51147 Setup 1u CHR 16,2 0t477304 3717 /dev/ttys002
bash 51147 Setup 2u CHR 16,2 0t477304 3717 /dev/ttys002
bash 51147 Setup 26u CHR 15,0 0t214349 579 /dev/ptmx
bash 51147 Setup 27u CHR 15,1 0t1206500 579 /dev/ptmx
bash 51147 Setup 254u CHR 16,2 0t477304 3717 /dev/ttys002
a
bash 51147 Setup 1u CHR 16,2 0t477304 3717 /dev/ttys002
bash 51147 Setup 2u CHR 16,2 0t477304 3717 /dev/ttys002
bash 51147 Setup 26u CHR 15,0 0t214349 579 /dev/ptmx
bash 51147 Setup 27u CHR 15,1 0t1206500 579 /dev/ptmx
bash 51147 Setup 254u CHR 16,2 0t477304 3717 /dev/ttys002
c
bash 51147 Setup 1u CHR 16,2 0t478702 3717 /dev/ttys002
bash 51147 Setup 2u CHR 16,2 0t478702 3717 /dev/ttys002
bash 51147 Setup 26u CHR 15,0 0t214349 579 /dev/ptmx
bash 51147 Setup 27u CHR 15,1 0t1206500 579 /dev/ptmx
bash 51147 Setup 254u CHR 16,2 0t478702 3717 /dev/ttys002
hi
stdout
ただし、forに識別子は表示されません。a
stdin
b
答え1
パイプは名前付きパイプとは異なり、匿名です。pipe(2)
注文する。ただし、明らかに内部IDが表示されていますlsof
(で確認できますls -l /proc/<pid>/fd
)。
しかし、stdoutの識別子が
a
stdinであることはわかりませんb
。
これはlsof
正しいプロセスを使用しないためです。$$
パイプコマンドによって生成されたサブシェルのPIDではなく、スクリプトPIDに展開されます。$BASHPID
代わりに使用する必要があります。
次のように関数を修正してください。
pipe() {
local pid=$BASHPID
printf '%s %s:%s %s\n' "$1" "$pid" "$BASH_SUBSHELL" $$ > /dev/stderr
printf '%s\n' "$1" "$(lsof -a -p "$pid" -d 0,1)" > /dev/stderr
cat
}
これで、次のような結果が得られます。
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 1290 xhienne 0r FIFO 0,12 0t0 180254229 pipe
bash 1290 xhienne 1w FIFO 0,12 0t0 180254230 pipe
...ここで、ノード番号はパイプの内部IDです。これにより、パイプ#12345678がstdoutをa
stdinb
などに接続することがわかります。