バックグラウンドプロセスが終了するまで関数が戻らないのはなぜですか?


21

次のスクリプトを検討してください。

#!/bin/bash
function start {
  leafpad &
  echo $!
}
PID=$(start)
echo "PID is $PID"

このスクリプトは、バックグラウンドプロセスであっても、リーフパッドプロセスが終了するまで閉じかっこを通過し続けません。

どうしてこれなの?関数からバックグラウンドプロセスを起動することはできますか?

回答:


22

この関数は戻りますが、バックグラウンドジョブを作成したが、stdout fdがまだ開いているため、コマンド置換はブロックされます。の>/dev/null前に追加して閉じ&ます。

#!/bin/bash
function start {
  leafpad >/dev/null &
  echo $!
}
PID=$(start)
echo "PID is $PID"

プロセスでstdin、stdout、stderrも閉じたい場合は、これを使用します。

leafpad >/dev/null 0>&1 2>&1 &

これにより、stdin(0)、stdout(1)、stderr(2)、そしてバックグラウンド(&)が閉じられます。また、これらのストリームリダイレクトを使用する場合、それらが「重複」していることを忘れないでください。つまり、実行順に複製されます。

1>/dev/null 2>&1

そして

2>&1 1>/dev/null

同じではありません!前者では、ストリームを/ dev / null(必要なもの)に複製しています。後者では、/ dev / stdoutをstderrに複製してから、stdoutを閉じています。したがって、送信されたメッセージはstderrコンソールに表示されます。


私のシステムで確認
user120161

10
ストリームを閉じているのではなく、リダイレクトしています。
dcat

4
閉じる n>&-ここnで、ファイル記述子です。
dcat

1
@dcat:はい。ただし/dev/null、プロセスがstdoutを書き込もうとしても、それが1無効なFDである場合、/へのリダイレクトはI / Oエラーにつながりません。したがって、投稿の用語は間違っており、実際のbashプログラミングではありません。(実際には、FD 1を0に複製すると、stdinがで開かれたファイル記述子にO_RDONLYなり、プロセスが読み取りを試みたときに(望ましいバイト数ではなく)エラーが発生する可能性があります。例wc >/dev/null 0>&1->wc: standard input: Bad file descriptor
Peter Cordes

1
@PeterCordes-古い記述子を閉じて新しい記述子をリダイレクトすることは、相互に排他的である必要はありません。exec <&- >&- <>/dev/null >&0stdin / outをかなり徹底的に処理します。zsh少なくとも違いは、multiosが設定されているときに、同じ記述子ですべてのオープンを自動的に連結することで異なります。
mikeserv
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.