Обнаружение нескольких запусков одного и того же ksh

Я пытаюсь определить, выполняется ли уже ksh script, чтобы предотвратить выполнение второго экземпляра.

Скрипт запускается каждую минуту пользователем cronjob:

* * * * * /home/user/job.ksh TESTACTION &>/dev/null

Я добавил охрану в начале скрипта:

#!/usr/bin/ksh

LOGDIR="/home/user"

processes=$(/bin/ps ux | /bin/grep -i "job.ksh TESTACTION" | /bin/grep -v grep | /bin/grep -c "\/usr\/bin\/ksh")
if (( $processes > 1 )); then
    datetime=$(/bin/date +'%Y.%m.%d %H:%M:%S')
    /bin/echo -e "${datetime} - skipped execution for other ${processes} active process" >> "${LOGDIR}/multiple_ksh_check.log"
    exit 0
fi

К моему удивлению, условие if выполняется часто, но не всегда, как я могу видеть из файла журнала.

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

Что мне не хватает? Что я могу попробовать?


person Francesco    schedule 30.06.2017    source источник
comment
Я бы начал с небольшой отладки; когда $processes > 1, также выгружает полный набор ps данных (т. е. не отфильтрованных через grep вызовы) в файл журнала; с полным набором ps данных вы, вероятно, обнаружите проблему с вашей логикой и / или дополнительную информацию о вашем сценарии оболочки, чтобы объяснить, почему $processes > 1   -  person markp-fuso    schedule 30.06.2017
comment
также ознакомьтесь с вопросами и ответами, которые могут применяться в вашем случае.   -  person markp-fuso    schedule 30.06.2017
comment
Я попытался сбросить все возможные ps выходные данные, чтобы убедиться, что логика работает. Теория подпроцесса кажется мне более разумным (и последним) объяснением, и я думаю, что в конечном итоге виноват $(/bin/ps ux), но как я могу обойти это?   -  person Francesco    schedule 30.06.2017
comment
Обычно я беру текущий идентификатор вызова (mypid=$$); затем отфильтруйте любые ps результаты, включающие $mypid; это должно отфильтровать текущий процесс (процесс = $mypid) плюс любые (недолговечные) дочерние процессы (родительский процесс = $mypid); что-то вроде egrep -v " ${mypid} " ... обратите внимание на пробел до / после $ {mypid}, чтобы в редких случаях мы не отфильтровывали 1234, когда mypid = 123   -  person markp-fuso    schedule 30.06.2017
comment
да, я работал над подобным решением, вдохновленным stackoverflow.com/a/25278679/1701296, в котором используется -w вариант grep, чтобы предотвратить проблему с подстрокой, о которой вы упомянули. Еще несколько тестов, но я думаю, что это то, что я искал, спасибо   -  person Francesco    schedule 30.06.2017
comment
да, вероятно, есть масса + 1 способов сделать это ... все, что работает, а; У меня есть несколько скриптов, которые должны обрабатывать несколько строк вывода ps, поэтому я выработал привычку использовать переменные ($ mypid, $ pid, $ ppid) для последующей обработки.   -  person markp-fuso    schedule 30.06.2017


Ответы (1)


Мне не хватало того, что оболочка может порождать подоболочки в других процессах, поэтому ps находил больше строк, чем ожидалось.

С некоторой помощью @markp и этого ответа я переписал условие следующим образом

processes=$(/bin/ps x -o pid,ppid,args | /bin/grep -vw $$ | /bin/grep -i "job.ksh TESTACTION" | /bin/grep -c "\/usr\/bin\/ksh")
if (( $processes > 0 )); then
     exit 0
fi

вот основные моменты:

  • The output of ps is formatted to include pid and parent pid information
    • I filter out the lines containing the current process'pid (contained into the special var $$)
    • таким образом мне не нужно отфильтровывать grep казней
    • Мне пришлось изменить проверку с 1 на 0, так как текущий процесс также был исключен из ps результатов.
person Francesco    schedule 03.07.2017