Bash:コマンドをバックグラウンドジョブに置き換える

Bash:コマンドをバックグラウンドジョブに置き換える

bash関数でプロセスをトリガーして忘れようとしています。私はこの関数がプロセスが実際にトリガされたという事実に対応する状態を返し、関数の出力を取得して子プロセスのPIDを取得したいと思います。だから私はこう書いています:

my_ping() {
    # ... param check which potentially return 1

    ping "$1" &
    local pid
    pid="$!"
    echo "$pid"
    return 0
}

コマンド置換とともに呼び出されると、関数はブロックされ、絶対に返されません(コマンド置換の外部はブロックされません)。

main() {
  
  # my_ping www.google.com # does not block and print PID

  # Blocks waiting for ping to terminate
  local mp_pid
  mp_pid=$(my_ping www.google.com)
}

main "$@"

この場合、なぜ関数がブロックされるのかわかりません。さまざまな方法(setsid、disownなど...)を試しましたが、成功しませんでしたが、何が起こっているのかわかりません。この状況を理解するのに役立つアドバイスはありますか?

答え1

pingデフォルト値(コマンド置換によって生成されたパイプライン)以外の場所に出力をリダイレクトする必要があります。プロセスがパイプの書き込みの終わりへの参照を保持している限り、デフォルトのシェルはEOFを取得せず、コマンド置換からすべての出力が取得されるまで待ち続けます。

たとえば、スクリプトの生の標準出力にリダイレクトするには、次のようにします。

my_ping() {
    ...
    ping "$1" >&"$out" &
    ...
}
main() {
    exec {out}>&1
    ...
    mp_pid=$(my_ping www.google.com)
}

関連情報