web-dev-qa-db-ja.com

bash:バックグラウンド関数プロセスを静かに強制終了します

シェルの達人、

Bashシェルスクリプトがあり、その中でfoo()などのバックグラウンド関数を起動して、退屈で長いコマンドの進行状況バーを表示します。

foo()
{
    while [ 1 ]
    do
        #massively cool progress bar display code
        sleep 1
    done
}

foo &
foo_pid=$!

boring_and_long_command
kill $foo_pid >/dev/null 2>&1
sleep 10

現在、fooが死ぬと、次のテキストが表示されます。

/home/user/script: line XXX: 30290 Killed                  foo

これは、それ以外の場合は非常にクールな進行状況バー表示のすばらしさを完全に破壊します。

このメッセージを削除するにはどうすればよいですか?

54
rouble
kill $foo_pid
wait $foo_pid 2>/dev/null

ところで、あなたの非常にクールなプログレスバーについては知りませんが、Pipe Viewer(pv)を見たことがありますか? http://www.ivarch.com/programs/pv.shtml

58
Mark Edgar

私はこれに出会ったばかりで、「否認」が私たちが探しているものであることに気付きました。

foo &
foo_pid=$!
disown

boring_and_long_command
kill $foo_pid
sleep 10

プロセスがまだ監視されている「ジョブ」のシェルリストにあるため、死のメッセージが出力されています。 disownコマンドは、最後に生成されたプロセスをこのリストから削除するため、SIGKILL(-9)を使用しても、終了時にデバッグメッセージは生成されません。

29
pix

行を置き換えてくださいkill $foo_pid >/dev/null 2>&1の行:

(kill $foo_pid 2>&1) >/dev/null

更新

@ mklement0のコメントで説明されている理由により、この答えは正しくありません。

バックグラウンドジョブでこの回答が効果的でない理由は、killコマンドが完了した後、Bash自体がキルされたジョブに関するステータスメッセージを出力するためです。

5
Sergei Kurenkov

これは、同様の問題(長時間実行されるプロセス中にタイムスタンプを表示することを望んでいた)のために思いついた解決策です。これは、pidを知っている限り、サブシェルを静かに強制終了できるkillsub関数を実装します。トラップ命令を含めることが重要であることに注意してください。スクリプトが中断された場合、サブシェルは実行を継続しません。

foo()
{
    while [ 1 ]
    do
        #massively cool progress bar display code
        sleep 1
    done
}

#Kills the sub process quietly
function killsub() 
{

    kill -9 ${1} 2>/dev/null
    wait ${1} 2>/dev/null

}

foo &
foo_pid=$!

#Add a trap incase of unexpected interruptions
trap 'killsub ${foo_pid}; exit' INT TERM EXIT

boring_and_long_command

#Kill foo after finished
killsub ${foo_pid}

#Reset trap
trap - INT TERM EXIT
4
bbbco

この「ハック」は機能しているようです:

# Some trickery to hide killed message
exec 3>&2          # 3 is now a copy of 2
exec 2> /dev/null  # 2 now points to /dev/null
kill $foo_pid >/dev/null 2>&1
sleep 1            # sleep to wait for process to die
exec 2>&3          # restore stderr to saved
exec 3>&-          # close saved version

here からインスピレーションを受けました。世界秩序が回復しました。

3
rouble

関数の最初に追加します:

trap 'exit 0' TERM
2
jilles

「待機」の使用に関しては、これが最良の答えだと思います。これがどのように見える/動作するかの例については、 https://stackoverflow.com/a/10200191/1208218 を参照してください。

0
Roel

それを抑制するには、前にset +mを使用できます。詳細については こちら

0
AhmadAssaf

別の方法:

    func_terminate_service(){

      [[ "$(pidof ${1})" ]] && killall ${1}
      sleep 2
      [[ "$(pidof ${1})" ]] && kill -9 "$(pidof ${1})" 

    }

と呼ぶ

    func_terminate_service "firefox"
0
Mike Q

ジョブ通知を無効にするさらにもう1つの方法は、コマンドをsh -c 'cmd &'コンストラクトにバックグラウンド化することです。

#!/bin/bash

foo()
{
   while [ 1 ]
   do
       sleep 1
   done
}

#foo &
#foo_pid=$!

export -f foo
foo_pid=`sh -c 'foo & echo ${!}' | head -1`

# if Shell does not support exporting functions (export -f foo)
#arg1='foo() { while [ 1 ]; do sleep 1; done; }'
#foo_pid=`sh -c 'eval "$1"; foo & echo ${!}' _ "$arg1" | head -1`


sleep 3
echo kill ${foo_pid}
kill ${foo_pid}
sleep 3
exit
0
phily