あるコマンドが別のコマンドにパイプされるかどうかを確認するには?

あるコマンドが別のコマンドにパイプされるかどうかを確認するには?

bash関数を使用してそれ自体に関するいくつかの情報をstderrにダンプし、それを呼び出してcatパイプラインを形成する場合、パイプラインのどのステップが別のステップを呼び出すかをどうやって知ることができますか?

1つの解決策は、各ステップに、、、、、などの名前を付けることです。aその後、出力を見るとわかります。しかし、ステップ名を指定したくないとしましょう。ステージのファイルディスクリプタを報告したステージが別のステージのファイルディスクリプタであることを確認して、前者が後者にパイプされていることを知る方法はありますか?では、共有パイプをどのように識別しますか?試してみましたが、チェーンの作り方がわかりません。bcda > b > c > dstdoutstdinlsof

例えば、

    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に識別子は表示されません。astdinb

答え1

パイプは名前付きパイプとは異なり、匿名です。pipe(2)注文する。ただし、明らかに内部IDが表示されていますlsof(で確認できますls -l /proc/<pid>/fd)。

しかし、stdoutの識別子がastdinであることはわかりません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をastdinbなどに接続することがわかります。

関連情報