كيف يمكنك قتل جميع عمليات Linux التي مضى عليها عمر معين؟

StackOverflow https://stackoverflow.com/questions/6134

  •  08-06-2019
  •  | 
  •  

سؤال

لدي مشكلة مع بعض العمليات الشبيهة بالزومبي على خادم معين والتي يجب قتلها بين الحين والآخر.كيف يمكنني التعرف بشكل أفضل على تلك التي استمرت لمدة تزيد عن ساعة أو نحو ذلك؟

هل كانت مفيدة؟

المحلول

إذا كانوا بحاجة فقط إلى القتل:

if [[ "$(uname)" = "Linux" ]];then killall --older-than 1h someprocessname;fi

إذا كنت تريد أن ترى ما هو مطابق

if [[ "$(uname)" = "Linux" ]];then killall -i --older-than 1h someprocessname;fi

ال -i ستطالبك العلامة بنعم/لا لكل عملية مطابقة.

نصائح أخرى

وجدت الإجابة التي تناسبني:

تحذير:هذا سوف تجد ويقتل عمليات تشغيل طويلة

ps -eo uid,pid,etime | egrep '^ *user-id' | egrep ' ([0-9]+-)?([0-9]{2}:?){3}' | awk '{print $2}' | xargs -I{} kill {}

(أين معرف المستخدم هو معرف مستخدم محدد مع عمليات طويلة الأمد.)

يتطابق التعبير العادي الثاني مع الوقت الذي يحتوي على رقم أيام اختياري، متبوعًا بالساعة والدقيقة والمكون الثاني، وبالتالي يبلغ طوله ساعة واحدة على الأقل.

لأي شيء مضى عليه أكثر من يوم واحد،

ps aux

سيعطيك الجواب، لكنه ينخفض ​​إلى دقة اليوم التي قد لا تكون مفيدة.

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   7200   308 ?        Ss   Jun22   0:02 init [5]
root         2  0.0  0.0      0     0 ?        S    Jun22   0:02 [migration/0]
root         3  0.0  0.0      0     0 ?        SN   Jun22   0:18 [ksoftirqd/0]
root         4  0.0  0.0      0     0 ?        S    Jun22   0:00 [watchdog/0]

إذا كنت تستخدم نظام Linux أو نظامًا آخر باستخدام نظام الملفات /proc، في هذا المثال، يمكنك فقط رؤية أن العملية 1 قد تم تشغيلها منذ 22 يونيو، ولكن لا توجد إشارة إلى وقت بدئها.

stat /proc/<pid>

سوف أعطيك إجابة أكثر دقة.على سبيل المثال، إليك الطابع الزمني الدقيق للعملية 1، والتي يظهر فيها ps كـ 22 يونيو فقط:

ohm ~$ stat /proc/1
  File: `/proc/1'
  Size: 0               Blocks: 0          IO Block: 4096   directory
Device: 3h/3d   Inode: 65538       Links: 5
Access: (0555/dr-xr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2008-06-22 15:37:44.347627750 -0700
Modify: 2008-06-22 15:37:44.347627750 -0700
Change: 2008-06-22 15:37:44.347627750 -0700

وبهذه الطريقة يمكنك الحصول على قائمة العمليات العشر الأقدم:

ps -elf | sort -r -k12 | head -n 10

وقد أشارت جودي سي وآخرون إلى ذلك killall -i يمكن استخدامه، وهو أمر جيد إذا كنت تريد استخدام اسم العملية للقتل.ولكن إذا كنت تريد أن تقتل بنفس المعلمات pgrep -f, ، تحتاج إلى استخدام شيء مثل ما يلي، باستخدام bash النقي و /proc نظام الملفات.

#!/bin/sh                                                                                                                                               

max_age=120 # (seconds)                                                                                                                                 
naughty="$(pgrep -f offlineimap)"                                                                                                                       
if [[ -n "$naughty" ]]; then # naughty is running                                                                                                       
  age_in_seconds=$(echo "$(date +%s) - $(stat -c %X /proc/$naughty)" | bc)                                                                              
  if [[ "$age_in_seconds" -ge "$max_age" ]]; then # naughty is too old!                                                                                 
    kill -s 9 "$naughty"                                                                                                                                
  fi                                                                                                                                                    
fi     

يتيح لك هذا العثور على العمليات الأقدم من عمرها وقتلها max_age ثواني باستخدام اسم العملية الكاملة;أي العملية المسماة /usr/bin/python2 offlineimap يمكن قتله بالرجوع إلى "offlineimap"، في حين أن killall الحلول المقدمة هنا ستعمل فقط على السلسلة "python2".

سوف يقوم Perl's Proc::ProcessTable بالمهمة:http://search.cpan.org/dist/Proc-ProcessTable/

يمكنك تثبيته على نظام دبيان أو أوبونتو sudo apt-get install libproc-processtable-perl

وهنا بطانة واحدة:

perl -MProc::ProcessTable -Mstrict -w -e 'my $anHourAgo = time-60*60; my $t = new Proc::ProcessTable;foreach my $p ( @{$t->table} ) { if ($p->start() < $anHourAgo) { print $p->pid, "\n" } }'

أو، بشكل أكثر تنسيقًا، ضع هذا في ملف يسمىprocess.pl:

#!/usr/bin/perl -w
use strict;
use Proc::ProcessTable;
my $anHourAgo = time-60*60;
my $t = new Proc::ProcessTable;
foreach my $p ( @{$t->table} ) {
    if ($p->start() < $anHourAgo) {
        print $p->pid, "\n";
    }
}

ثم اركض perl process.pl

يمنحك هذا مزيدًا من التنوع ودقة تبلغ ثانية واحدة في وقت البدء.

يمكنك استخدام bc للانضمام إلى الأمرين في إجابة الغوغاء ومعرفة عدد الثواني المنقضية منذ بدء العملية:

echo `date +%s` - `stat -t /proc/<pid> | awk '{print $14}'` | bc

يحرر:

بسبب الملل أثناء انتظار العمليات الطويلة، هذا ما ظهر بعد بضع دقائق من العبث:

#file: sincetime
#!/bin/bash
init=`stat -t /proc/$1 | awk '{print $14}'`
curr=`date +%s`
seconds=`echo $curr - $init| bc`
name=`cat /proc/$1/cmdline`
echo $name $seconds

إذا وضعت هذا في طريقك وسميته هكذا:منذ زمن

فإنه سيتم طباعة cmdline العملية والثواني منذ البداية.يمكنك أيضًا وضع هذا في طريقك:

#file: greptime
#!/bin/bash
pidlist=`ps ax | grep -i -E $1 | grep -v grep | awk '{print $1}' | grep -v PID | xargs echo`
for pid in $pidlist; do
    sincetime $pid
done

وماذا لو ركضت:

greptime <pattern>

عندما تكون الأنماط عبارة عن سلسلة أو تعبير عادي ممتد، فإنها ستطبع جميع العمليات المطابقة لهذا النمط والثواني منذ بدايتها.:)

افعل أ ps -aef.سيُظهر لك هذا الوقت الذي بدأت فيه العملية.ثم باستخدام date الأمر العثور على الوقت الحالي.احسب الفرق بين الاثنين لمعرفة عمر العملية.

لقد فعلت شيئًا مشابهًا للإجابة المقبولة ولكن بشكل مختلف قليلاً لأنني أريد المطابقة بناءً على اسم العملية وعلى أساس العملية السيئة التي تعمل لأكثر من 100 ثانية

kill $(ps -o pid,bsdtime -p $(pgrep bad_process) | awk '{ if ($RN > 1 && $2 > 100) { print $1; }}')

stat -t /proc/<pid> | awk '{print $14}'

للحصول على وقت بدء العملية بالثواني منذ العصر.قارن مع الوقت الحالي (date +%s) للحصول على العمر الحالي للعملية.

استخدام ps هو الطريق الصحيح.لقد قمت بالفعل بشيء مماثل من قبل ولكن ليس لدي المصدر في متناول يدي.بشكل عام - يحتوي ps على خيار لإخباره بالحقول التي سيتم إظهارها والتي سيتم فرزها.يمكنك فرز المخرجات حسب وقت التشغيل، والتعامل مع العملية التي تريدها ثم إيقافها.

هث

في حال احتاج أي شخص إلى ذلك في لغة C، يمكنك استخدام readproc.h و libproc:

#include <proc/readproc.h>
#include <proc/sysinfo.h>

float
pid_age(pid_t pid)
{
        proc_t proc_info;
        int seconds_since_boot = uptime(0,0);
        if (!get_proc_stats(pid, &proc_info)) {
                return 0.0;
        }

        // readproc.h comment lies about what proc_t.start_time is. It's
        // actually expressed in Hertz ticks since boot

        int  seconds_since_1970 = time(NULL);
        int time_of_boot = seconds_since_1970 - seconds_since_boot;
        long  t = seconds_since_boot - (unsigned long)(proc_info.start_time / Hertz);

        int delta = t;
        float days = ((float) delta / (float)(60*60*24));
        return days;
}

جئت عبر مكان ما.. أعتقد أنه بسيط ومفيد

يمكنك استخدام الأمر في crontab مباشرة،

* * * * * ps -lf | grep "user" |  perl -ane '($h,$m,$s) = split /:/,$F
+[13]; kill 9, $F[3] if ($h > 1);'

أو يمكننا كتابته كبرنامج شل،

#!/bin/sh
# longprockill.sh
ps -lf | grep "user" |  perl -ane '($h,$m,$s) = split /:/,$F[13]; kill
+ 9, $F[3] if ($h > 1);'

ونسميها crontab هكذا،

* * * * * longprockill.sh

نسختي من sincetime أعلاه بواسطة @ رافائيل س.كالسافيريني :

#!/bin/bash
ps --no-headers -o etimes,args "$1"

يؤدي هذا إلى عكس حقول الإخراج:الوقت المنقضي أولاً، الأمر الكامل بما في ذلك الوسائط ثانيًا.يُفضل هذا لأن الأمر الكامل قد يحتوي على مسافات.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top