web-dev-qa-db-ja.com

シェルスクリプト出力からstdout / stderrを抑制する方法は?

プロセスを停止して回復し、バックグラウンドで実行することを想定したスクリプトがあります。

process_id=`ps -eaf | grep -i daemon | grep -v grep | grep -v status | grep -v stop | awk '{print $2}'`
(kill -STOP $process_id) &
... # do something else 
(kill -CONT $process_id) &

これは正常に機能していますが、STDOUT/STDERRでは次のように表示されます。

[1]  +  8545 Suspended (signal)            /etc/init.d/...

これまでのところ、私はしようとしました:

(kill -STOP $process_id)

(kill -STOP $process_id) & > /dev/null

/etc/init.d/{name_of_the_daemon} start > /dev/null

(kill -STOP $process_id & ) 2>/dev/null 

(kill -STOP $process_id & disown;) 2>/dev/null 

set +m
(kill -STOP $process_id) & 

(kill -STOP $process_id) & 1>&2

これらは私がしているステップです:

  1. /etc/init.d/にファイルfffを作成します
  2. 下からスクリプトを貼り付けます
  3. chmod 755 fff
  4. /etc/init.d/fff start

その後、「一時停止」のメッセージが表示されます...

@sourcejediによると、私のスクリプトはデーモンではありません。スクリプトの子プロセスが一時停止されると、「一時停止」メッセージが表示されます

その特定のメッセージに対してのみシェルからの出力を抑制するにはどうすればよいですか?

これが私のスクリプトの非常に単純なバージョンです。

#!/bin/bash

pid_script=`ps -eaf | grep -i fff | grep -v grep | grep -v status | grep -v stop | awk '{print $2}'`

case "$1" in
    start)
    ( sleep 3; kill -STOP $pid_script ) &
    sleep 10;
    (sleep 1; kill -CONT $pid_script) &
    ;;
    stop)
    for p in $pid_script # kill all the other processes related with this script (if any)
        do
            kill -9 $p
        done
esac
4
toom501

[1] + 7766 Suspended (signal) ...が表示されている場合、これはシェルによって出力されたメッセージであり、その子プロセスの1つが中断されていることを示しています。

fffの例では、考慮すべき2つのシェルプロセスがあります。最初のインタラクティブシェル、および子プロセスとして実行されるシェルスクリプト。

スクリプトはそれ自体を一時停止するように調整します。 「Suspended」メッセージは、インタラクティブシェルによって出力されます。したがって、これはオンとオフを切り替えることができるオプションではありませんスクリプト内

さらに、この特定のメッセージのオンとオフを切り替えるためにインタラクティブシェルで設定できるオプションはありません。このメッセージを個別に「抑制する」ことはできません...基本的にこれはあなたがやりたいことではないからです:-)。

とにかく、fffスクリプトは正常に再開しないと思います。そうするためにそれを修正することは可能かもしれないと思います。しかし、それ自体を再開することは恐ろしい考えです。スクリプトを一時停止すると、インタラクティブシェルはコマンドプロンプトを再度表示します。つまり「一時停止」メッセージが表示されない場合は、スクリプトが終了したように見えます。しかし、いずれにせよ、スクリプトがそれ自体を再開することができた場合、その間にユーザーが何を始めたかに関係なく、ユーザーから端末の制御を奪おうとします。これは良くない!


私はあなたが例えばを理解する必要があると思います。端末からプロセスを起動し、それがインタラクティブシェルの子プロセスである場合、それはdaemonプロセスではありません。

端末からdaemonを起動するには、起動時にプログラム自体がfork()する必要があります。元のプロセスは終了する必要があり、これにより、継続するプロセスをre-parentedにすることができます。 (従来のUNIXでは)PID 1 a.k.a. initプロセス。また、ターミナルから切り離すために、さらに多くの手順を含める必要があります。たとえば、ここを参照してください: シェルでプロセスをデーモン化しますか?

さらに、システムでsystemdを使用する場合は、レガシー_/etc/init.d/_スクリプトを_systemctl start_を使用して開始する必要があることを理解する必要があります。 Debianや他の場所でパッケージ化された_init.d_スクリプトには、これを行う互換性ハックが含まれています。ただし、notを使用する必要があります。混乱のレシピです。作成したスクリプトにはこの機能がないため、必須 _systemctl start fff_を使用します。

fffスクリプトのゲームを_systemctl start_と組み合わせて使用​​しないことを強くお勧めします。

実際には、systemctlはバックグラウンドサービスプロセスを開始するために別のアプローチを使用します。 PID 1(systemd initプロセス)にメッセージを送信し、PID 1は要求されたプログラムを開始します。ネイティブsystemdサービスを定義する場合、プログラムはそれ自体をデーモン化する必要はありません。従来の_init.d_スクリプトを使用する場合でも、プログラムはそれ自体をデーモン化する必要がありますが、systemdに_init.d_スクリプトの開始が完了したことを通知するだけです。 (残念ながら多くの既存のプログラムにはデーモン化ステップの後に起こり得る起動の失敗がありますが、これはデーモンのいくつかの起動の失敗に気付くことを可能にします)。

systemdが_init.d_スクリプトの停止と再開に反応するかどうか、またどのように反応するかについて心配する必要はありません。

2
sourcejedi

私があなたの目標を正しく理解しているかどうかはわかりませんが、これが私にとってどのように機能するかです:

  1. 「デーモン」を開始します。実際には、プロセスを継続的に実行します:top -d1 >out

  2. 2番目のターミナルでは、必要に応じてtail -f outできます

  3. 3番目のターミナルでkill -STOP $(ps -eFH | grep "top -d" |grep -v grep|awk '{print $2}'を実行します

デーモンが開始された最初のターミナルに「suspended」メッセージが表示されますが、outファイルにはそのようなメッセージはありません。

0
Putnik