Как я могу убить процесс и быть уверенным, что PID не был повторно использован


40

Предположим, например, что у вас есть скрипт оболочки, похожий на:

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

Должен сделать трюк, не так ли? За исключением того, что процесс мог завершиться досрочно, а его PID, возможно, был переработан, а это означает, что некоторые невинные работы вместо этого получают бомбу в своей очереди сигналов. На практике это, возможно, имеет значение, но, тем не менее, меня это беспокоит. Взлом longrunningthing для того, чтобы упасть замертво, или сохранить / удалить свой PID на FS, подойдет, но я думаю об общей ситуации здесь.


3
Вы убедитесь, что если ваш целевой процесс умирает, он убивает его убийцу в процессе.
mikeserv

2
Используйте, killallкоторый соответствует по имени, так что, по крайней мере, вы убиваете только процесс с тем же именем, что и longrunningthing. Предполагая, что у вас будет только один из них одновременно.
LawrenceC

8
Вы можете сохранить время начала исходного процесса и, перед тем как убить, проверить, что время начала процесса с этим pid соответствует тому, что вы сохранили. Пара pid, start-time - это уникальный идентификатор процессов в Linux.
Бакуриу

1
Могу я спросить, зачем тебе это? Какую фундаментальную вещь вы пытаетесь достичь? (что-то, что работает непрерывно, но сбрасывается каждые 24 часа?)
Оливье Дюлак

2
@mikeserv Процесс не может гарантировать, что что-то случится в случае его собственной смерти.
Касперд

Ответы:


29

Лучше всего использовать timeoutкоманду, если она у вас есть:

timeout 86400 cmd

Текущая реализация (8.23) GNU по крайней мере работает с использованием alarm()или эквивалентным образом, ожидая дочерний процесс. Похоже, он не защищает от SIGALRMдоставки между waitpid()возвращением и timeoutвыходом (фактически отменяя эту тревогу ). В течение этого небольшого окна timeoutможет даже писать сообщения на stderr (например, если дочерний объект сбросил ядро), что еще больше увеличит это окно гонки (на неопределенное время, если, например, stderr - полный канал).

Я лично могу жить с этим ограничением (которое, вероятно, будет исправлено в будущей версии). 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()механизм, похожий на другой, но устанавливает обработчик SIGCHLD(игнорируя остановленных потомков), чтобы обнаружить умирающего ребенка. Он также отменяет сигнал тревоги перед запуском waitpid()(это не отменяет доставку, SIGALRMесли она ожидала, но так, как написано, я не вижу в этом проблемы) и убивает перед вызовом waitpid()(поэтому не может убить повторно использованный pid ).

У netpipes также есть timelimitкоманда. Тот, кто предшествует всем остальным на десятилетия, использует еще один подход, но не работает должным образом для остановленных команд и возвращает состояние 1выхода по истечении времени ожидания.

Как более прямой ответ на ваш вопрос, вы можете сделать что-то вроде:

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

То есть проверьте, что этот процесс все еще является нашим ребенком. Опять же, есть небольшое окно гонки (между psполучением статуса этого процесса и killего уничтожением), во время которого процесс может умереть и его pid может быть использован другим процессом.

С некоторыми оболочками ( zsh, bash, mksh), вы можете передать функции задания вместо ИДП.

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

Это работает только в том случае, если вы создаете только одну фоновую работу (в противном случае получение правильной спецификации задания не всегда возможно надежно).

Если это проблема, просто запустите новый экземпляр оболочки:

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

Это работает, потому что оболочка удаляет задание из таблицы заданий после смерти ребенка. Здесь не должно быть никакого гоночного окна, так как к тому времени, когда оболочка вызывает kill(), либо сигнал SIGCHLD не был обработан, и pid не может быть повторно использован (так как он не ожидался), либо он был обработан и задание было удалено из таблицы процессов (и killбудет сообщать об ошибке). bash«S по killкрайней мере блоков SIGCHLD , прежде чем он получает доступ к таблице заданий , чтобы расширить %и разблокирует его после kill().

Еще один вариант, чтобы избежать sleepзависания этого процесса даже после cmdего смерти, с помощью bashили ksh93использовать трубу 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)

Тем не менее, обратите внимание, что использование групп процессов может иметь побочные эффекты, если имеется ввод-вывод для терминального устройства. Это имеет дополнительное преимущество, хотя убивает все другие дополнительные процессы, порожденные cmd.


4
Почему бы не упомянуть лучший метод в первую очередь?
Дельтаб

2
@deltab: timeoutне переносимо, в ответе сначала упоминается переносимое решение.
cuonglm

1
@deltab: он дает представление о том, как все работает, и особенно о том, как подход «здравого смысла» может потерпеть неудачу (Стефан предпочитает сначала научить его ловить рыбу, что мне нравится). Ожидается, что весь ответ прочитают
Оливье Дюлак

@Stephane: для «получения правильной спецификации заданий не всегда возможно надежно»: вы не можете сначала посчитать вывод, jobsа затем узнать, что (поскольку это ваша собственная оболочка, в которой вы можете контролировать то, что происходит дальше), следующая фоновая среда работа будет N + 1? [тогда вы можете спасти N, а затем убить% N + 1])
Оливье Дюлак

1
@OlivierDulac, который предполагает, что ни одно из прошлых заданий не было прервано к тому времени, когда вы запускаете новое (оболочки используют номера заданий повторно).
Стефан Шазелас

28

В общем, вы не можете. Все ответы, данные до сих пор, являются ошибочной эвристикой. Существует только один случай, когда вы можете безопасно использовать pid для отправки сигналов: когда целевой процесс является прямым потомком процесса, который будет отправлять сигнал, а родитель еще не ожидал его. В этом случае, даже если он вышел, pid зарезервирован (это и есть «процесс зомби»), пока родитель не будет ожидать его. Я не знаю ни одного способа сделать это чисто с оболочкой.

Альтернативный безопасный способ уничтожения процессов - запуск их с управляющим набором tty для псевдотерминала, для которого у вас есть главная сторона. Затем вы можете отправлять сигналы через терминал, например, записывая символ для SIGTERMили SIGQUITнад pty.

Еще один способ, более удобный для сценариев, - использовать именованный screenсеанс и посылать команды сеансу экрана для его завершения. Этот процесс происходит по каналу или сокету unix, названному в соответствии с сеансом экрана, который не будет автоматически использоваться повторно, если вы выберете безопасное уникальное имя.


4
Я не понимаю, почему это не может быть сделано в снарядах. Я дал несколько решений.
Стефан Шазелас

3
Не могли бы вы дать объяснение и какое-то количественное обсуждение расовых окон и других недостатков? Без этого, «все ответы, приведенные до сих пор, являются ошибочной эвристикой» , это просто излишне конфронтационное без каких-либо преимуществ.
Петер

3
@peterph: В общем, любое использование pid - это гонка TOCTOU - независимо от того, как вы проверяете, относится ли он к тому же процессу, на который вы ожидаете, он может перестать ссылаться на этот процесс и обратиться к некоторому новому обрабатывать в интервале, прежде чем использовать его (отправка сигнала). Единственный способ предотвратить это - иметь возможность заблокировать освобождение / повторное использование pid, и единственный процесс, который может это сделать, - это прямой родитель.
R ..

2
@ StéphaneChazelas: Как вы предотвращаете ожидание оболочки на pid фонового процесса, который завершился? Если вы можете сделать это, проблема легко решается в случае необходимости ОП.
R ..

5
@peterph: «Окно гонки мало» - это не решение проблемы. И редкость гонки зависит от последовательного назначения pid. Ошибки, которые вызывают что-то очень плохое один раз в год, гораздо хуже, чем ошибки, которые происходят постоянно, потому что их практически невозможно диагностировать и исправлять.
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
    

Это работает, потому что в данной ОС может быть только один процесс с одинаковым PID и временем запуска.

Остановка процесса во время проверки делает условия гонки несущественными. Очевидно, что проблема заключается в том, что некоторый случайный процесс может быть остановлен на несколько миллисекунд. В зависимости от типа процесса это может или не может быть проблемой.


Лично я бы просто использовал 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()

Правила Python в UNIX ... Я не уверен, почему там не начинается больше ответов, так как я уверен, что большинство систем не запрещают его использование.
Г - н Маскаро

Я использовал аналогичную схему (используя время запуска) раньше, но ваши навыки написания скриптов аккуратнее моих! Спасибо.
FJL

Это означает, что вы можете остановить неправильный процесс. Обратите внимание, что ps -o start=формат меняется с 18:12 на 26 января через некоторое время. Остерегайтесь изменений летнего времени. Если на Linux, вы, вероятно, предпочтете TZ=UTC0 ps -o lstart=.
Стефан Шазелас

@ StéphaneChazelas Да, но потом вы позволите этому продолжаться. Я прямо сказал: в зависимости от типа задачи, которую выполняет этот процесс, у вас могут возникнуть проблемы с остановкой на несколько миллисекунд. Спасибо за совет lstart, я отредактирую его.
Бакуриу

Обратите внимание, что (если ваша система не ограничивает число процессов на пользователя), любой может легко заполнить таблицу процессов зомби. Когда осталось только 3 доступных пида, любой может легко запустить сотни различных процессов с одним и тем же пидом в течение одной секунды. Таким образом, строго говоря, ваш «может быть только один процесс с одинаковым PID и временем запуска в данной ОС» не обязательно соответствует действительности.
Стефан Шазелас

7

В системе linux вы можете гарантировать, что pid не будет использоваться повторно, поддерживая его пространство имен pid живым. Это можно сделать через /proc/$pid/ns/pidфайл.

  • man namespaces -

    Привязать монтирование (см. mount(2)) К одному из файлов в этом каталоге где-то еще в файловой системе поддерживает соответствующее пространство имен процесса, указанного в pid, даже если все процессы, находящиеся в данный момент в пространстве имен, завершаются.

    Открытие одного из файлов в этом каталоге (или файла, подключенного к одному из этих файлов) возвращает дескриптор файла для соответствующего пространства имен процесса, указанного в pid. Пока этот файловый дескриптор остается открытым, пространство имен остается живым, даже если все процессы в пространстве имен завершаются. Файловый дескриптор может быть передан setns(2).

Вы можете изолировать группу процессов - в основном любое количество процессов - путем присвоения им пространства имен init.

  • man pid_namespaces -

    Первый процесс, созданный в новом пространстве имен (т. Е. Процесс, созданный clone(2) с использованием флага CLONE_NEWPID , или первый дочерний элемент, созданный процессом после вызова с unshare(2)использованием флага CLONE_NEWPID ), имеет PID 1 и является initпроцессом для пространства имен ( смотри init(1)) . Дочерний процесс, осиротевший в пространстве имен, будет переименован в этот процесс, а не init(1) (если только один из предков дочернего элемента в том же пространстве имен PID не использовал команду prctl(2) 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 '...'

...и так далее.

В приведенном выше примере два переключателя передаются unshare(1)на --forkфлаг , который делает Вызванный sh -cпроцесс создан первый ребенок и обеспечивает его initстатус, и --pidфлаг , который инструктирует unshare(1)для создания Pid пространства имен.

Этот sh -cпроцесс порождает пять дочерних оболочек, каждая из которых является бесконечным whileциклом, который будет продолжать добавлять выходные данные dateв конец до logтех пор, пока sleep 1возвращается значение true. После запуска этих процессов shвызовы sleepдополнительных 5 секунд, а затем завершается.

Возможно, стоит отметить, что если бы -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. Сама man-страница, которую вы цитируете - пока этот дескриптор файла остается открытым, пространство имен останется живым, даже если все процессы в пространстве имен завершатся, - предполагает, что процессы могут все еще завершиться (и, следовательно, предположительно, их идентификатор процесса будет перезагружен). Какое отношение поддерживает поддержание пространства имен PID с предотвращением повторного использования самого PID другим процессом?
Давмак

5

Подумайте о том, чтобы заставить longrunningthingсебя вести себя немного лучше, чуть более похожим на демона. Например, вы можете сделать так, чтобы он создал pid-файл , который позволит хотя бы ограничить контроль над процессом. Есть несколько способов сделать это без изменения исходного двоичного файла, все с использованием обертки. Например:

  1. простой скрипт-обертка, который запустит требуемое задание в фоновом режиме (с необязательным перенаправлением вывода), запишите PID этого процесса в файл, затем дождитесь завершения процесса (используя wait) и удалите файл. Если во время ожидания процесс будет убит, например, чем-то вроде

    kill $(cat pidfile)
    

    Оболочка просто убедится, что pid-файл удален.

  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, эти подходы часто имеют где-то состояние гонки или накладывают ограничение на количество процессов, которые вы можете порождать. Кроме того, он не обрабатывает случаи, когда longrunningthingмайский ответвление и дочерние элементы отсоединяются (что, вероятно, не было проблемой в первоначальном вопросе).

С недавними (читай пару лет) ядрами Linux это можно легко решить с помощью cgroups , а именно морозильной камеры - которую, я полагаю, используют некоторые современные системы инициализации Linux.


Спасибо и всем. Сейчас я читаю все. Суть в longrunningthingтом, что вы не можете контролировать, что это такое. Я также привел пример сценария оболочки, потому что он объяснил проблему. Мне нравятся ваши и все другие креативные решения здесь, но если вы используете Linux / bash, для этого есть встроенный тайм-аут. Я полагаю, я должен получить источник этого и посмотреть, как он это делает!
FJL

@FJL, timeoutэто не встроенная оболочка. Было несколько реализаций timeoutкоманды для Linux, одна из которых (2008) была добавлена ​​в GNU coreutils (поэтому не специфична для Linux), и это то, что в настоящее время используется большинством дистрибутивов Linux.
Стефан Шазелас

@ Стефан - Спасибо - я впоследствии нашел ссылку на GNU coreutils. Они могут быть переносными, но если на них нет базовой системы, на них нельзя положиться. Мне больше интересно знать, как это работает, хотя я отмечаю ваш комментарий в другом месте о том, что он не на 100% надежен. Учитывая, как прошла эта тема, я не удивлен!
FJL

1

Если вы работаете в Linux (и некоторых других * nixes), вы можете проверить, используется ли все еще процесс, который вы собираетесь убить и соответствует ли командная строка вашему длинному процессу. Что-то типа :

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 10.09.15

@strcat Действительно, нет гарантии успеха, но большинство сценариев даже не удосуживаются выполнить такую ​​проверку и только тупо убивают cat pidfileрезультат. Я не могу вспомнить чистый способ сделать это только в оболочке. Предложенный ответ пространства имен кажется интересным, однако ...
Уриэль

-1

Это на самом деле очень хороший вопрос.

Способ определения уникальности процесса состоит в том, чтобы посмотреть: а) где он находится в памяти; и (б) что эта память содержит. В частности, мы хотим знать, где в памяти находится текст программы для первоначального вызова, потому что мы знаем, что текстовая область каждого потока будет занимать другое место в памяти. Если процесс умирает, а другой запускается с тем же pid, текст программы для нового процесса не будет занимать одно и то же место в памяти и не будет содержать ту же информацию.

Итак, сразу после запуска вашего процесса, сделайте md5sum /proc/[pid]/mapsи сохраните результат. Позже, когда вы захотите завершить процесс, сделайте еще одну md5sum и сравните ее. Если это соответствует, тогда убейте pid. Если нет, не надо.

чтобы убедиться в этом, запустите две одинаковые оболочки bash. Изучите /proc/[pid]/mapsих, и вы обнаружите, что они разные. Зачем? Потому что, хотя это одна и та же программа, они занимают разные места в памяти и адреса их стека различны. Таким образом, если ваш процесс умирает и его PID используется повторно, даже при повторном запуске одной и той же команды с теми же аргументами , файл «maps» будет другим, и вы будете знать, что не имеете дело с исходным процессом.

Подробности смотрите на странице справочника proc .

Обратите внимание, что файл /proc/[pid]/statуже содержит всю информацию, которую другие авторы упомянули в своих ответах: возраст процесса, родительский pid и т. Д. Этот файл содержит как статическую, так и динамическую информацию, поэтому, если вы предпочитаете использовать этот файл в качестве основы сравнения, после запуска longrunningthingвам нужно извлечь из statфайла следующие статические поля и сохранить их для сравнения позже:

pid, имя файла, pid родителя, идентификатор группы процессов, управляющий терминал, время запуска процесса после загрузки системы, размер резидентного набора, адрес начала стека,

вместе взятые, выше однозначно идентифицируют процесс, и поэтому это представляет собой другой путь. На самом деле, вы можете с легкостью доверять только «pid» и «процесс времени, запущенный после загрузки системы». Просто извлеките эти поля из statфайла и сохраните их где-нибудь после запуска вашего процесса. Позже, прежде чем убить его, извлеките его снова и сравните. Если они совпадают, то вы уверены, что смотрите на оригинальный процесс.


1
Как правило, это не будет работать с /proc/[pid]/mapsтечением времени, так как выделяется дополнительная память, увеличивается размер стека или появляются новые файлы ... А что означает сразу после запуска ? После того, как все библиотеки были отображены? Как вы это определяете?
Стефан Шазелас

Сейчас я провожу тестирование в моей системе с двумя процессами, одним из которых является приложение Java, а другим - сервер cfengine. Каждые 15 минут я делаю md5sumна своих картах файлы. Я позволю этому работать в течение дня или два и сообщу здесь с результатами.
Майкл Мартинес

@ StéphaneChazelas: я проверял свои два процесса в течение 16 часов, и в md5sum не было никаких изменений
Майкл Мартинес,

-1

Другим способом было бы проверить возраст процесса, прежде чем убить его. Таким образом, вы можете быть уверены, что не убиваете процесс, который не был создан менее чем за 24 часа. Вы можете добавить ifусловие, основанное на этом, прежде чем убить процесс.

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

Это ifусловие проверяет, является ли идентификатор процесса $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 ~ $ 

Не может быть проще, и я делал это годами без проблем.


Это ответ на вопрос «как я могу сделать это хуже», а не «как я могу это исправить».
Стефан Шазелас
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.