プロセスを強制終了し、PIDが再利用されていないことを確認する方法


40

たとえば、次のようなシェルスクリプトがあるとします。

longrunningthing &
p=$!
echo Killing longrunningthing on PID $p in 24 hours
sleep 86400
echo Time up!
kill $p

トリックを行う必要がありますか?プロセスが早期に終了し、そのPIDがリサイクルされた可能性があることを除いて、いくつかの罪のないジョブが代わりにシグナルキューで爆弾を取得することを意味します。実際にはこれは問題になる可能性がありますが、それでも私は心配しています。長時間実行しているものをハッキングして、それ自体を落とす、またはFSでPIDを保持/削除することはできますが、ここでは一般的な状況を考えています。


3
ターゲットプロセスが死んだ場合、そのプロセスでそのキラーを殺すことを確認します。
mikeserv

2
killall名前に一致するものを使用します。少なくとも、と同じ名前のプロセスのみを強制終了しますlongrunningthing。一度に実行されるのはこれらのうちの1つだけであると仮定します。
ローレンス

8
元のプロセスの開始時間を保存し、強制終了する前に、そのpidを持つプロセスの開始時間が保存したものと一致することを確認できます。pid、start-timeのペア、Linuxのプロセスの一意の識別子です。
バクリウ

1
私が聞いても、なぜあなたはこれを必要としますか?あなたが達成しようとしている基本的なことは何ですか?(継続的に実行されるものの、24時間ごとにリセットされるもの)
オリビエデュラック

2
@mikeservプロセスは、自身が死んだ場合に何かが起こることを保証できません。
カスペルド

回答:


29

そのためのtimeoutコマンドがある場合は、コマンドを使用することをお勧めします。

timeout 86400 cmd

現在(8.23)のGNU実装は、少なくともalarm()子プロセスを待機している間に使用するか、同等のものを使用して動作します。戻ることと終了SIGALRMすることの間に配信されることを保護していないようです(そのアラームを効果的にキャンセルします)。その小さなウィンドウの間に、(たとえば、子がコアをダンプした場合)stderrにメッセージを書き込むこともあります。これにより、そのレースウィンドウがさらに大きくなります(たとえば、stderrがフルパイプの場合)。waitpid()timeouttimeout

私は個人的にその制限に耐えることができます(おそらく将来のバージョンで修正されるでしょう)。timeoutまた、適切な終了ステータスを報告し、他のコーナーケース(SIGALRMが起動時にブロック/無視される、他の信号を処理するなど)を処理するのに、おそらく手でやるよりも十分に注意します。

近似として、次のように書くことができますperl

perl -MPOSIX -e '
  $p = fork();
  die "fork: $!\n" unless defined($p);
  if ($p) {
    $SIG{ALRM} = sub {
      kill "TERM", $p;
      exit 124;
    };
    alarm(86400);
    wait;
    exit (WIFSIGNALED($?) ? WTERMSIG($?)+128 : WEXITSTATUS($?))
  } else {exec @ARGV}' cmd

http://devel.ringlet.net/sysutils/timelimit/にtimelimitコマンドがあります(GNU timeoutよりも数か月前です)。

 timelimit -t 86400 cmd

それはalarm()-likeメカニズムを使用しますが、ハンドラーをインストールしSIGCHLD(停止した子を無視)、子の死を検出します。また、実行前にアラームをキャンセルしwaitpid()SIGALRM保留中だった場合は配信をキャンセルしませんが、書き込み方法が問題であることがわかりません)、呼び出す前に殺しますwaitpid()(したがって、再利用されたpidを殺すことはできません) )。

netpipesにtimelimitコマンドがあります。それは他のすべてのものよりも数十年前に行われ、さらに別のアプローチを取りますが、停止したコマンドに対して適切に機能せず1、タイムアウト時に終了ステータスを返します。

あなたの質問に対するより直接的な答えとして、あなたは次のようなことをすることができます:

if [ "$(ps -o ppid= -p "$p")" -eq "$$" ]; then
  kill "$p"
fi

つまり、プロセスがまだ私たちの子であることを確認してください。繰り返しますが、プロセスが終了し、そのpidが別のプロセスによって再利用される可能性のある小さな競合ウィンドウがあります(psそのプロセスのステータスの取得と終了の間kill)。

一部のシェルでは(zshbashmksh)は、ジョブの仕様の代わりのPIDを渡すことができます。

cmd &
sleep 86400
kill %
wait "$!" # to retrieve the exit status

これは、バックグラウンドジョブを1つだけ生成する場合にのみ機能します(そうしないと、正しいjobspecを取得できるとは限りません)。

問題がある場合は、新しいシェルインスタンスを開始するだけです。

bash -c '"$@" & sleep 86400; kill %; wait "$!"' sh cmd

これは、子が死んだときにシェルがジョブテーブルからジョブを削除するためです。ここでは、シェルがを呼び出すkill()までに、SIGCHLDシグナルが処理されず、pidを再利用できない(待機していないため)か、処理されて、ジョブはプロセステーブルから削除されました(killエラーが報告されます)。bash「S killそれが拡大してそのジョブ表にアクセスする前に、少なくともブロックのSIGCHLDで%と後のブロックを解除kill()

それを避けるために別のオプションsleepの後でもぶらぶらプロセスはcmdと、死亡したbashksh93とのパイプを使用することですread -t代わりにsleep

{
  {
    cmd 4>&1 >&3 3>&- &
    printf '%d\n.' "$!"
  } | {
    read p
    read -t 86400 || kill "$p"
  }
} 3>&1

これにはまだ競合状態があり、コマンドの終了ステータスが失われます。またcmd、fd 4を閉じないことも想定しています。

次のperlような競合のないソリューションを実装してみてください。

perl -MPOSIX -e '
   $p = fork();
   die "fork: $!\n" unless defined($p);
   if ($p) {
     $SIG{CHLD} = sub {
       $ss = POSIX::SigSet->new(SIGALRM); $oss = POSIX::SigSet->new;
       sigprocmask(SIG_BLOCK, $ss, $oss);
       waitpid($p,WNOHANG);
       exit (WIFSIGNALED($?) ? WTERMSIG($?)+128 : WEXITSTATUS($?))
           unless $? == -1;
       sigprocmask(SIG_UNBLOCK, $oss);
     };
     $SIG{ALRM} = sub {
       kill "TERM", $p;
       exit 124;
     };
     alarm(86400);
     pause while 1;
   } else {exec @ARGV}' cmd args...

(ただし、他のタイプのコーナーケースを処理するには改善する必要があります)。

別の競合のない方法は、プロセスグループを使用することです。

set -m
((sleep 86400; kill 0) & exec cmd)

ただし、関連する端末デバイスへのI / Oがある場合、プロセスグループの使用には副作用があることに注意してください。ただし、によって生成される他のすべての追加プロセスを強制終了することには、追加の利点がありますcmd


4
最初に最良の方法を挙げてみませんか?
デルタブ

2
@deltab:timeout移植性がありません。最初の回答は移植性のあるソリューションです。
クオンルム

1
@deltab:物事がどのように機能するか、特に「常識」アプローチがどのように失敗するかについての洞察を提供します(Stephaneは最初に釣りを教えることを好むので、これが好きです)。答え全体を読むことが期待されます
オリビエデュラック

@Stephane:「正しいjobspecを取得することが常に確実に可能とは限らない」ため:最初に出力を数え、jobsそれから(それはあなた自身のシェルであるため、次に何が起こるかを制御できます)仕事はN + 1になりますか?[その後、Nを保存し、後で%N + 1を殺すことができます])
オリビエデュラック

1
@OlivierDulacは、新しいジョブを開始するまでに過去のジョブが終了していないと仮定します(シェルはジョブ番号を再利用します)。
ステファンシャゼル

28

一般的にはできません。これまでに与えられた答えはすべて、バグのあるヒューリスティックです。pidを安全に使用してシグナルを送信できるのは、ターゲットプロセスがシグナルを送信するプロセスの直接の子であり、親がまだ待機していない場合です。この場合、たとえ終了したとしても、親が待機するまでpidは予約されています(これが "ゾンビプロセス"です)。私は、シェルでそれをきれいに行う方法を知りません。

プロセスを強制終了する別の安全な方法は、マスター側を所有する疑似端末に設定された制御ttyでプロセスを開始することです。その後、ターミナルを介して信号を送信できます。たとえば、ptyの文字を書き込むSIGTERMSIGQUIT、ptyを介して文字を書き込みます。

スクリプトでさらに便利なもう1つの方法は、名前付きscreenセッションを使用し、スクリーンセッションにコマンドを送信して終了することです。このプロセスは、スクリーンセッションに従って名前が付けられたパイプまたはUNIXソケットで行われます。安全な一意の名前を選択した場合、これらは自動的に再利用されません。


4
シェルでそれができなかった理由がわかりません。いくつかのソリューションを提供しました。
ステファンシャゼラス

3
レースウィンドウやその他の欠点についての説明と定量的な説明をお願いします。それがなければ、「これまでに与えられた答えはすべてバグのあるヒューリスティックです」は、メリットのない不必要な対立にすぎません。
ペテルフ

3
@peterph:一般に、pidの使用はTOCTOUレースです-参照する予定の同じプロセスを参照しているかどうかをどのように確認しても、そのプロセスを参照しなくなり、新しいプロセスを参照することができます使用する前に間隔で処理します(信号を送信します)。これを防ぐ唯一の方法は、pidの解放/再利用をブロックできるようにすることであり、これを行うことができるプロセスは直接の親だけです。
R ..

2
@StéphaneChazelas:終了したバックグラウンドプロセスのPIDでシェルが待機するのをどのように防ぐのですか?それができれば、OPが必要な場合に問題は簡単に解決できます。
R ..

5
@peterph:「レースウィンドウが小さい」というのは解決策ではありません。そして、レースの希少性は、連続的なpidの割り当てに依存しています。1年に1回非常に悪いことを引き起こすバグは、診断と修正が事実上不可能であるため、常に起こるバグよりもはるかに悪いです。
R ..

10
  1. プロセスを起動するとき、開始時間を節約します。

    longrunningthing &
    p=$!
    stime=$(TZ=UTC0 ps -p "$p" -o lstart=)
    
    echo "Killing longrunningthing on PID $p in 24 hours"
    sleep 86400
    echo Time up!
    
  2. プロセスを強制終了する前に、それを停止します(これは本当に必須ではありませんが、競合状態を回避する方法です。プロセスを停止すると、pidは再利用できません)

    kill -s STOP "$p"
    
  3. そのPIDのプロセスが同じ開始時間を持っていることを確認し、そうであれば、それを強制終了します。

    cur=$(TZ=UTC0 ps -p "$p" -o lstart=)
    
    if [ "$cur" = "$stime" ]
    then
        # Okay, we can kill that process
        kill "$p"
    else
        # PID was reused. Better unblock the process!
        echo "long running task already completed!"
        kill -s CONT "$p"
    fi
    

これは、特定のOSで同じPID 開始時刻を持つプロセスが1つしか存在できないために機能します。

チェック中にプロセスを停止すると、競合状態は問題になりません。これには明らかに、ランダムなプロセスが数ミリ秒間停止するという問題があります。プロセスのタイプに応じて、これは問題になる場合とそうでない場合があります。


個人的に私は単にPythonを使用psutilし、PIDの再利用を自動的に処理します:

import time

import psutil

# note: it would be better if you were able to avoid using
#       shell=True here.
proc = psutil.Process('longrunningtask', shell=True)
time.sleep(86400)

# PID reuse handled by the library, no need to worry.
proc.terminate()   # or: proc.kill()

UNIXでのPythonのルール...ほとんどのシステムがその使用を禁止していないと確信しているため、なぜそこから答えが出ないのかわかりません。
氏Mascaro

以前にも同様のスキーム(開始時間を使用)を使用しましたが、shスクリプトのスキルは私のものよりも優れています!ありがとう。
FJL

つまり、間違ったプロセスを潜在的に停止していることになります。ps -o start=しばらくすると形式が18:12からJan26に変わることに注意してください。DSTの変更にも注意してください。Linuxの場合、おそらくお勧めですTZ=UTC0 ps -o lstart=
ステファンシャゼル

@StéphaneChazelasはい、しかしその後は継続させます。私は明示的に言った:そのプロセスが実行しているタスクのタイプによっては、それを数ミリ秒停止するのに問題があるかもしれません。のヒントをありがとうlstart、私はそれを編集します
。-バクリウ

(システムがユーザーあたりのプロセス数を制限していない限り)誰でも簡単にプロセステーブルにゾンビを入れることができることに注意してください。使用可能なPIDが3つしか残っていない場合、誰でも1秒以内に同じPIDで数百の異なるプロセスを簡単に開始できます。したがって、厳密に言うと、「特定のOSで同じPIDと開始時刻を持つプロセスは1つしか存在できない」ということは必ずしも当てはまりません。
ステファンシャゼル

7

Linuxシステムでは、pid名前空間を有効に保つことで、pidが再利用されないことを保証できます。これは、/proc/$pid/ns/pidファイルを介して実行できます。

  • man namespaces -

    このディレクトリ内のファイルの1つをファイルシステム内の別の場所にバインド(参照mount(2)すると、現在ネームスペースにあるすべてのプロセスが終了しても、pidで指定されたプロセスの対応するネームスペースが保持されます。

    このディレクトリ内のファイルの1つ(またはこれらのファイルの1つにバインドされたファイル)を開くと、pidで指定されたプロセスの対応するネームスペースのファイルハンドルが返されます。このファイル記述子が開いている限り、名前空間内のすべてのプロセスが終了しても、名前空間は生きたままになります。ファイル記述子はに渡すことができますsetns(2)

プロセスのグループ-基本的には任意の数のプロセス-を名前空間で分離できますinit

  • man pid_namespaces -

    新しい名前空間で作成された最初のプロセス(すなわち、使用して作成されたプロセスclone(2)CLONE_NEWPIDフラグ、またはの呼び出し後の処理によって作成された最初の子unshare(2)使って CLONE_NEWPIDフラグ)が持っているPID 1を、そしてあるinit名前空間のためのプロセス(を参照init(1)。ネームスペース内で孤立している子プロセスはinit(1) 、同じprctl(2) プロセスではなく親プロセスになります(同じPIDネームスペース内の子の祖先の1つがPR_SET_CHILD_SUBREAPERコマンドを使用して、孤立した子孫プロセスのリーパーとしてマークします)

    場合initのプロセスPID名前空間が終了すると、カーネルは、経由して、名前空間内のすべてのプロセスを終了させるSIGKILLの シグナル。この動作は、initプロセスがPID名前空間の正しい操作に不可欠であることを反映しています。

このutil-linuxパッケージには、名前空間を操作するための便利なツールが多数用意されています。たとえば、がありunshareますが、ユーザーの名前空間でその権限をまだ手配していない場合は、スーパーユーザーの権限が必要です。

unshare -fp sh -c 'n=
    echo "PID = $$"
    until   [ "$((n+=1))" -gt 5 ]
    do      while   sleep 1
            do      date
            done    >>log 2>/dev/null   &
    done;   sleep 5' >log
cat log; sleep 2
echo 2 secs later...
tail -n1 log

ユーザー名前空間を用意していない場合でも、すぐに特権を削除することにより、任意のコマンドを安全に実行できます。runuserコマンドは別である(非setuidさ)が提供するバイナリutil-linuxパッケージと、それは次のようになります組み込みます:

sudo unshare -fp runuser -u "$USER" -- sh -c '...'

...等々。

上記の例では2つのスイッチに渡されるときに呼び出させるフラグ最初の子が作成されたプロセスを、その保証のステータス、および指示フラグPID名前空間を作成します。unshare(1)--forksh -cinit--pidunshare(1)

sh -cプロセススポーン5つのバックグラウンドに、子の殻-各inifinite whileの出力を追加していきますループdateの最後にlog限りとしてのためにsleep 1trueを返します。これらのプロセスを生成した後、さらに5秒間sh呼び出しsleepてから終了します。

-fフラグが使用されなかった場合、バックグラウンドwhileループはどれも終了しませんが、それで...

出力:

PID = 1
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:48 PST 2015
Mon Jan 26 19:17:48 PST 2015
Mon Jan 26 19:17:48 PST 2015
Mon Jan 26 19:17:48 PST 2015
Mon Jan 26 19:17:48 PST 2015
2 secs later...
Mon Jan 26 19:17:48 PST 2015

堅牢であると思われる興味深い答え。おそらく基本的な使用法では少し過剰ですが、考えてみる価値があります。
ウリエル

PID名前空間を維持すると、PIDの再利用がどのように、またはなぜ妨げられるかわかりません。あなたが引用したまさにマンページ- このファイル記述子が開いている限り、名前空間のすべてのプロセスが終了しても、名前空間は生きたままになります -プロセスがまだ終了する可能性があることを示唆しています(したがって、おそらくプロセスIDがリサイクルされています)。PID名前空間を有効に保つことは、PID自体が別のプロセスによって再利用されるのを防ぐことに関係しますか?
-davmac

5

longrunningthing少しだけデーモンのように振る舞うようにすることを検討してください。たとえば、プロセスの少なくとも一部の制限された制御を可能にするpidfileを作成することができます。元のバイナリを変更せずにこれを行う方法はいくつかあり、すべてラッパーが関係します。例えば:

  1. バックグラウンドで必要なジョブを開始し(オプションの出力リダイレクトを使用)、このプロセスのPIDをファイルに書き込み、プロセスが完了するのを待って(を使用してwait)ファイルを削除する単純なラッパースクリプト。待機中にプロセスが次のように強制終了される場合

    kill $(cat pidfile)
    

    ラッパーは、pidfileが削除されたことを確認するだけです。

  2. モニタラッパー。独自の PIDをどこかに配置し送信された信号をキャッチ(および応答)します。簡単な例:

    #!/bin/bash
    p=0
    trap killit USR1

    killit () {
        printf "USR1 caught, killing %s\n" "$p"
        kill -9 $p
    }

    printf "monitor $$ is waiting\n"
    therealstuff &
    p=%1
    wait $p
    printf "monitor exiting\n"

さて、@ R ..と@StéphaneChazelasが指摘したように、これらのアプローチはしばしばどこかで競合状態を持っているか、生成できるプロセスの数に制限を課しています。さらに、longrunningthingmayフォークと子が切り離されるケースを処理しません(これはおそらく元の質問の問題ではなかったでしょう)。

最近の(数年前に読まれた)Linuxカーネルでは、これはcgroups、つまりフリーザーを使用することでうまく処理できます。これは、現代のLinux initシステムで使用されているものと思われます。


ありがとう、そしてすべての人に。私は今すべてを読んでいます。ポイントlongrunningthingはあなたがそれが何であるかを制御できないということです。問題を説明したので、シェルスクリプトの例も示しました。私はあなたの、そしてここにある他のすべてのクリエイティブなソリューションが好きですが、Linux / bashを使用している場合は、そのための「タイムアウト」ビルトインがあります。ソースを取得して、それがどのように機能するかを確認する必要があると思います!
FJL

@FJL timeoutは、シェル組み込みではありませんtimeoutLinux用のコマンドにはさまざまな実装がありますが、最近(2008年)GNU coreutilsに追加されました(Linux固有ではありません)。これは現在、ほとんどのLinuxディストリビューションで使用されています。
ステファンシャゼル

@Stéphane-ありがとう-その後、GNU coreutilsへの参照を見つけました。それらは移植可能かもしれませんが、ベースシステムにない限り信頼できません。私はそれがどのように機能するかを知ることにもっと興味がありますが、100%信頼できるものではないことを示唆するあなたのコメントに注意しています。このスレッドが行った方法を考えると、私は驚きません!
FJL

1

Linux(および他のいくつかの* nix)で実行している場合は、強制終了するプロセスがまだ使用されいるかどうか、およびコマンドラインが長いプロセスと一致するかどうかを確認できます。何かのようなもの :

echo Time up!
grep -q longrunningthing /proc/$p/cmdline 2>/dev/null
if [ $? -eq 0 ]
then
  kill $p
fi

別の方法として、強制終了するプロセスの実行時間を確認することもできますps -p $p -o etime=。この情報をから抽出することで自分で行うことができます/proc/$p/statが、これには注意が必要です(時間は短時間で測定されるため、システムの稼働時間/proc/statも使用する必要があります)。

とにかく、通常、チェック、強制終了する前にプロセスが置き換えられないことを保証できません。


競合状態を解消しないため、それはまだ正しくありません。
-strcat

@strcat確かに、成功の保証はありませんが、ほとんどのスクリプトはそのようなチェックを行うことさえせず、cat pidfile結果を鈍く殺すだけです。シェルでのみ行うクリーンな方法を思い出せません。ただし、提案された名前空間の回答は
Uriel

-1

これは実際には非常に良い質問です。

プロセスの一意性を判断する方法は、(a)メモリ内の場所を確認することです。(b)そのメモリに含まれるもの。具体的には、各スレッドのテキスト領域がメモリ内の異なる場所を占めることがわかっているため、メモリ内のどこが最初の呼び出しのプログラムテキストであるかを知りたいのです。プロセスが停止し、別のプロセスが同じpidで起動された場合、新しいプロセスのプログラムテキストはメモリ内の同じ場所を占有せず、同じ情報を含みません。

したがって、プロセスを起動した直後にmd5sum /proc/[pid]/maps、結果を保存してください。後でプロセスを強制終了する場合は、別のmd5sumを実行して比較します。一致する場合は、pidを強制終了します。そうでない場合は、しないでください。

これを自分で確認するには、2つの同一のbashシェルを起動します。調べ/proc/[pid]/maps彼らのために、あなたは彼らが異なっていることがわかります。どうして?同じプログラムであっても、メモリ内の異なる場所を占有し、スタックのアドレスが異なるためです。そのため、同じコマンドを同じ引数再起動しても、プロセスが停止してそのPIDが再利用される場合、「マップ」ファイルは異なり、元のプロセスを処理していないことがわかります。

詳細については、procのマニュアルページを参照してください。

ファイルに/proc/[pid]/statは、他の投稿者が回答で言及したすべての情報が既に含まれていることに注意してください。プロセスの年齢、親pidなど。このファイルには静的情報と動的情報の両方が含まれます。比較の場合、を起動するlongrunningthingと、statファイルから次の静的フィールドを抽出し、後で比較するためにそれらを保存する必要があります。

pid、ファイル名、親のpid、プロセスグループID、制御端末、システムブート後に開始された時間プロセス、常駐セットサイズ、スタックの開始アドレス、

上記を合わせてプロセスを一意に識別するため、これは別の方法を表します。実際には、「pid」と「システム起動後に開始される時間プロセス」だけで、高い信頼性で逃げることができます。これらのフィールドをstatファイルから抽出し、プロセスの起動時にどこかに保存するだけです。後でそれを殺す前に、それを再び抽出して比較します。それらが一致する場合、元のプロセスを見ていることが保証されます。


1
通常/proc/[pid]/maps、追加のメモリが割り当てられたり、スタックが大きくなったり、新しいファイルがマッピングされると、時間の経過とともに変化しません。そして、起動直後はどうなりますか?すべてのライブラリがマッピングされた後?それをどのように判断しますか?
ステファンシャゼル

現在、システムで2つのプロセス(1つはJavaアプリ、もう1つはcfengineサーバー)でテストを行っています。15分ごとmd5sumに、マップファイルを作成します。1〜2日実行して、結果をここに報告します。
マイケルマルティネス

StéphaneChazelas@:私は今、16時間のための私の二つのプロセスをチェックしてきた、とのmd5sumで変更がないだ
マイケル・マルティネス

-1

別の方法は、プロセスを終了する前にプロセスの経過時間をチェックすることです。これにより、24時間以内に生成されないプロセスを強制終了しないようにすることができます。ifプロセスを強制終了する前に、それに基づいて条件を追加できます。

if [[ $(ps -p $p -o etime=) =~ 1-. ]] ; then
    kill $p
fi

このif条件は、プロセスID $pが24時間(86400秒)未満であるかどうかを確認します。

PS:-コマンドps -p $p -o etime=の形式は<no.of days>-HH:MM:SS


mtimeのは、/proc/$pプロセスの開始時刻とは何の関係もありません。
ステファンシャゼル

@StéphaneChazelasに感謝します。あなたが正しいです。答えを編集してif条件を変更しました。バグがある場合はお気軽にコメントしてください。
スリー

-3

私がしていることは、プロセスを強制終了した後、再度実行することです。私がするたびに、答えは「そのようなプロセスはありません」と戻ってきます

allenb   12084  5473  0 08:12 pts/4    00:00:00 man man
allenb@allenb-P7812 ~ $ kill -9 12084
allenb@allenb-P7812 ~ $ kill -9 12084
bash: kill: (12084) - No such process
allenb@allenb-P7812 ~ $ 

これ以上簡単にすることはできず、何年も問題なくこれを行ってきました。


それは、「どうすれば修正できるか」ではなく、「どうすればそれを悪化させることができるか」という質問に答えていることです。
ステファンシャゼラス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.