ジョブIDとプロセスIDを出力せずにバックグラウンドでbashコマンドを実行する


83

bashでバックグラウンドでプロセスを実行するのはかなり簡単です。

$ echo "Hello I'm a background task" &
[1] 2076
Hello I'm a background task
[1]+  Done                    echo "Hello I'm a background task"

ただし、出力は冗長です。最初の行には、バックグラウンドタスクのジョブIDとプロセスIDが出力され、次にコマンドの出力が表示され、最後にジョブID、そのステータス、およびジョブをトリガーしたコマンドが表示されます。

バックグラウンドタスクの実行の出力を抑制して、出力が最後にアンパサンドがない場合とまったく同じように見えるようにする方法はありますか?すなわち:

$ echo "Hello I'm a background task" &
Hello I'm a background task

私が尋ねる理由は、タブ補完コマンドの一部としてバックグラウンドプロセスを実行したいので、そのコマンドの出力が意味をなさないようにする必要があるためです。


bash-completionスクリプト内で行うすべての操作に2> / dev / nullを追加する必要があると思います
2011年

回答:


98

完了とは関係ありませんが、呼び出しをサブシェルに入れることで、その出力を抑制することができます。

(echo "Hello I'm a background task" &)

3
おかげで、それは間違いなく機能します。残念ながら、bash-completion関数からこのようなスクリプトを実行すると、bashはサブプロセスが完了するまで待機してから、完了結果を返すように見えます。これは、バックグラウンドワーカーをbashの完了によってトリガーさせることができないように見えるため、残念です。
Alex Spurling 2011年

13
waitバックグラウンドジョブを終了させたい場合は、これを使用できません。
arekolek 2017年

13

@shellterの答えに基づいて、これは私にとってはうまくいきました:

tyler@Tyler-Linux:~$ { echo "Hello I'm a background task" & disown; } 2>/dev/null; sleep .1;
Hello I'm a background task
tyler@Tyler-Linux:~$

この背後にある理由はわかりませんが、bashがプロセスIDを出力できないという古い投稿を思い出しました。


@Tyzoid。私はあなたのソリューションをbashシェル(v 4.2.37)で試しましたが、興味深い結果が得られました。1.;最後に追加するだけで同じ結果が得られました。(寝ないで) 。2.しかしecho STDERR 2>&1、「次の」行に追加すると、そのことが表示されたことに気づきました[1]+ Done ...。。3.私の解決策は、(私が今述べてきたように)で動作kshし、echo STDERR 2>&1出力のみのSTDERRを生成します。さて、私たちの両方のために生きて学びましょう。皆さんお元気で。
シェルター2017年

12

一部の新しいバージョンのbashおよびksh93では、サブシェルまたはプロセスグループ(つまり{ ... })で囲むことができます。

/home/shellter $ { echo "Hello I'm a background task" & } 2>/dev/null
Hello I'm a background task
/home/shellter $

5
中括弧を使用すると、出力の最後の行が引き続き表示されます(なぜ表示されないのかわかりません)。
Alex Spurling 2011年

これを正確にコピーしましたが、機能しません。@ AlexSpurlingが言うように出力が表示されます。他の人が賛成したので、私は何か間違ったことをしているのかもしれませんが、私はそれを-1にする必要があるのではないかと心配しています。
マーク

1
@Mark:これを使って簡単なテストを行ったところksh93+、プライマリシェルとして引き続き使用していることが問題であることがわかりました。このコードは、kshで約束されたとおりに機能します。しかし、OPがタグ付けされbashているので、私はあなたのdvを理解しています。@Tyzoidの回答でbashテストの結果を参照してください。皆さんお元気で!
シェルター2017年

これはbashでは機能しないことを明確にしたので、-1を削除します。
マーク

1
私にとって、これはBash関数でうまく機能します。またwait $!、受け入れられた回答には当てはまらないように見えるプロセスを待つこともできます。
はJonatanオストロム


6

この答えに基づいて、私はより簡潔で正しいものを思いついた:

silent_background() {
    { 2>&3 "$@"& } 3>&2 2>/dev/null
    disown &>/dev/null  # Prevent whine if job has already completed
}
silent_background date

完璧!他のものに再利用可能
user230910 2018年

5

試してみてください:

user@host:~$ read < <( echo "Hello I'm a background task" & echo $! )
user@host:~$ echo $REPLY
28677

そして、出力PIDの両方を非表示にしました。$ REPLYからPIDを取得できることに注意してください


1
これは完璧です!ありがとう
Adham Atta 2017年

4

古い投稿への返信で申し訳ありませんが、これは他の人にも役立つと思います。これはGoogleでの最初の返信です。

このメソッド(サブシェル)で問題が発生し、「wait」を使用していました。ただし、関数内で実行していたため、次のことができました。

function a {
    echo "I'm background task $1"
    sleep 5
}

function b {
    for i in {1..10}; do
        a $i &
    done
    wait
} 2>/dev/null

そして私がそれを実行すると:

$ b
I'm background task 1
I'm background task 3
I'm background task 2
I'm background task 4
I'm background task 6
I'm background task 7
I'm background task 5
I'm background task 9
I'm background task 8
I'm background task 10

また、プロンプトが返されるまでに5秒の遅延があります。


1

サブシェルソリューションは機能しますが、バックグラウンドジョブを待機できるようにしたかったのです(最後に「完了」メッセージが表示されないようにしました)。$!現在の対話型シェルでは、サブシェルからの送信は「待機可能」ではありません。私のために働いた唯一の解決策は、非常に単純な独自の待機関数を使用することでした。

myWait() {
  while true; do
    sleep 1; STOP=1
    for p in $*; do
      ps -p $p >/dev/null && STOP=0 && break
    done
    ((STOP==1)) && return 0
  done
}

i=0
((i++)); p[$i]=$(do_whatever1 & echo $!)
((i++)); p[$i]=$(do_whatever2 & echo $!)
..
myWait ${p[*]}

簡単です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.