web-dev-qa-db-ja.com

bashで殺した後、終了したメッセージを抑制する方法は?

Bashスクリプトでプロセスを強制終了した後に表示されるTerminatedメッセージをどのように抑制できますか?

set +bmを試しましたが、うまくいきません。

私は別の解決策がexec 2> /dev/nullを呼び出すことを含むことを知っていますが、それは信頼できますか? stderrを引き続き表示できるように、どのようにリセットしますか?

51
user14437

短い答えは、できないということです。 Bashは常にフォアグラウンドジョブのステータスを出力します。監視フラグはバックグラウンドジョブにのみ適用され、スクリプトではなく対話型シェルにのみ適用されます。

jobs.cのnotify_of_job_status()を参照してください。

あなたが言うように、標準エラーが/ dev/nullを指しているようにリダイレクトできますが、他のエラーメッセージを見逃します。スクリプトを実行するサブシェルでリダイレクトを行うことにより、一時的にすることができます。これにより、元の環境はそのままになります。

(script 2> /dev/null)

エラーメッセージはすべて失われますが、シェルで実行される他のスクリプトからではなく、そのスクリプトからのみ失われます。

新しいファイル記述子をリダイレクトすることで、標準エラーを保存および復元できます:

exec 3>&2          # 3 is now a copy of 2
exec 2> /dev/null  # 2 now points to /dev/null
script             # run script with redirected stderr
exec 2>&3          # restore stderr to saved
exec 3>&-          # close saved version

しかし、私はこれをお勧めしません-最初のものからの唯一の利点は、サブシェルの呼び出しを保存することですが、より複雑であり、スクリプトがファイル記述子を変更する場合はスクリプトの動作を変更することさえあります。


編集:

Mark Edgarによって与えられるより適切な回答チェックの回答

16
wnoise

メッセージを黙らせるためには、メッセージが生成されるときにstderrをリダイレクトする必要がありますkill コマンドはシグナルを送信し、ターゲットプロセスが応答するのを待たないため、stderrコマンドのkillをリダイレクトすると、良い。 bashビルトイン wait は、この目的のために特別に作成されました。

これは、最新のバックグラウンドコマンドを強制終了する非常に簡単な例です。 ( $!の詳細はこちら

kill $!
wait $! 2>/dev/null

killwaitの両方が複数のpidを受け入れるため、バッチキルも実行できます。以下は、(もちろん現在のプロセス/スクリプトの)すべてのバックグラウンドプロセスを強制終了する例です。

kill $(jobs -rp)
wait $(jobs -rp) 2>/dev/null

ここから bash:バックグラウンド関数プロセスを静かに終了します から導かれました。

121
Mark Edgar

MarcHの答え に触発されました。私はkill -INTを使用していましたが、彼はいくつかの成功をお勧めしましたが、一部のプロセスを強制終了していないことに気付きました。他のいくつかのシグナルをテストした後、メッセージなしでSIGPIPEも殺すことがわかります。

kill -PIPE

または単に

kill -13
16
Steven Penny

解決策:SIGINTを使用します(非対話型シェルでのみ動作します)

デモ:

cat > silent.sh <<"EOF"
sleep 100 &
kill -INT $!
sleep 1
EOF

sh silent.sh

http://thread.gmane.org/gmane.comp.shells.bash.bugs/15798

8
MarcH

disownを呼び出して、現在のシェルプロセスからプロセスをデタッチすることもできますか?

4

これは私たち全員が探しているものですか?

要らない:

$ sleep 3 &
[1] 234
<pressing enter a few times....>
$
$
[1]+  Done                    sleep 3
$

募集:

$ (set +m; sleep 3 &)
<again, pressing enter several times....>
$
$
$
$
$

ご覧のとおり、ジョブ終了メッセージはありません。 bashスクリプトでも、バックグラウンドプロセスの強制終了でも機能します。

「set + m」は、現在のシェルのジョブ制御を無効にします(「help set」を参照)。したがって、サブシェルでコマンドを入力する場合(括弧内で実行)、現在のシェルのジョブ制御設定に影響を与えません。唯一の欠点は、終了したかどうかを確認する場合、または戻りコードを評価する場合、バックグラウンドプロセスのpidを現在のシェルに戻す必要があることです。

1
Ralph

これはkillallでも機能します(それを好む人のために):

killall -s SIGINT (yourprogram) 

メッセージを抑制します...バックグラウンドモードでmpg123を実行していました。 SIGTERM(デフォルト)の代わりにctrl-c(SIGINT)を送信することで、静かに殺すことができました。

1

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

#!/bin/bash
# ...
pid="`sh -c 'sleep 30 & echo ${!}' | head -1`"
kill "$pid"
# ...

# or put several cmds in sh -c '...' construct
sh -c '
sleep 30 &
pid="${!}"
sleep 5 
kill "${pid}"
'
1
phily

シンプル:

{ kill $! } 2>/dev/null

利点?任意の信号を使用できます

例:

{ kill -9 $PID } 2>/dev/null
0
user2429558

disownは私にとってまさに正しいことをしました-exec 3>&2は多くの理由で危険です-set + bmはコマンドプロンプトでのみスクリプト内で動作するようには見えませんでした

0
clemep

関数にkillコマンドを入れてから関数をバックグラウンド化すると、終了出力が抑制されることがわかりました

function killCmd() {
    kill $1
}

killCmd $somePID &
0
Al Joslin

'jobs 2>&1 >/dev/null'をスクリプトに追加することに成功しました。他の人のスクリプトに役立つかどうかは不明ですが、ここにサンプルがあります。

    while true; do echo $RANDOM; done | while read line
    do
    echo Random is $line the last jobid is $(jobs -lp)
    jobs 2>&1 >/dev/null
    sleep 3
    done
0
J-o-h-n-