📜 ⬆️ ⬇️

Bash: we start the demon with child processes

Good all the mood!
I read this article , and decided to take the checkers in my hands for a bit, and try to do something pleasant for myself and for others.
My script does not do any useful things, but I think for less novice writers on bash, he will teach something, and even if there are comments, then I will learn from those people who point out my mistakes.

Introductory

The script will be run in the background by the daemon. Immediately I think it is necessary to agree that the process itself which will hang in my memory all the time I will call “Parent”. The parent will search for a specific file in a specific directory, and if it exists, the file will be deleted and a process will be launched, which I will call the “Descendant”, the purpose of which will simply sleep for a while and then end. But the Parent will not have to run more than one Descendant per unit of time. In principle, if you read the above article, then I think the meaning is clear.

Let's start with

So, we define our variables.
#        FILE_NAME="run_Lola_run" #       WATCH_DIR="/home/mcleod/test" #           LOCK_FILE="${WATCH_DIR}/monitor_file.lock" #         PID_FILE="${WATCH_DIR}/monitor_file.pid" #          JOB_LOCK_FILE="${WATCH_DIR}/job_monitor_file.lock" #         LOG="${WATCH_DIR}/monitor_file_work.log" #          ERR_LOG="${WATCH_DIR}/monitor_file_error.log" #        RANGE=100 


Next, for convenient management of starting and stopping the Parent, we will write a small condition
 case $1 in "start") start ;; "stop") stop ;; *) usage ;; esac exit 

')
The frame is ready, all the variables are also defined, now we need to describe the functions used


Now I will describe the functions as they become more complex. The simplest of them is the usage function, it looks like this
 #   usage() { echo "$0 (start|stop)" } 

Next comes the _log function.
 #   _log() { process=$1 shift echo "${process}[$$]: $*" } 

Now the daemon stop function
 #    stop() { #   pid ,       pid  if [ -e ${PID_FILE} ] then _pid=$(cat ${PID_FILE}) kill $_pid rt=$? if [ "$rt" == "0" ] then echo "Daemon stop" else echo "Error stop daemon" fi else echo "Daemon is't running" fi } 

Here I do not use the logging function, since here messages should be displayed on the console.
Now perhaps bring the most complex function start. It contains all the logic of the work and the very moment of the demonization of the script.
 #    start() { #     pid        if [ -e $PID_FILE ] then _pid=$(cat ${PID_FILE}) if [ -e /proc/${_pid} ] then echo "Daemon already running with pid = $_pid" exit 0 fi fi #    touch ${LOG} touch ${ERR_LOG} #   ,      cd / #   ,      exec > $LOG exec 2> $ERR_LOG exec < /dev/null #    ,  .      ( #             trap "{ rm -f ${PID_FILE}; exit 255; }" TERM INT EXIT #     while [ 1 ] do #      if ls -1 ${WATCH_DIR} | grep "^${FILE_NAME}$" 2>&1 >/dev/null then _log "parent" "File found" rm -f ${WATCH_DIR}/${FILE_NAME} _log "parent" "File deleted" #            number=$RANDOM let "number %= $RANGE" _log "parent" "Genereated number $number" JOBS[${#JOBS[@]}]=$number fi #     0,   ,       if [ "${#JOBS[@]}" -gt "0" ] then if [ ! -e ${JOB_LOCK_FILE} ] then run_job _log "parent" "Running job with pid $!" unset JOBS[0] JOBS=("${JOBS[@]}") _log "parent" "Jobs in queue [${#JOBS[@]}]" fi fi #    sleep 1 done exit 0 )& #  pid   ,    echo $! > ${PID_FILE} } 

Well, the launch function itself
 #   .       JOBS,   run_job() { #    .          /, ..      ( #        trap "{ rm -f ${JOB_LOCK_FILE}; exit 255; }" TERM INT EXIT #         if [ ! -e ${JOB_LOCK_FILE} ] then #   pid   ,    echo "$$" > ${JOB_LOCK_FILE} _log "child" "Job with pid $$" #     seconds=${JOBS[0]} #  ,     ,      unset JOBS _log "child" "Sleep seconds $seconds" sleep ${seconds} else _log "child" "Lock file is exists" fi #  exit 0 )& } 

Well, now if all of the above merged into a file and give it the right to execute, I think it will not be difficult for you. By the way, before launching, I advise you to change the value of the WATCH_DIR variable to the path to the directory in which the script will look for a file named run_Lola_run.
Here is my log file output
 parent[32338]: File found parent[32338]: File deleted parent[32338]: Genereated number 96 parent[32338]: Running job with pid 32385 parent[32338]: Jobs in queue [0] child[32338]: Job with pid 32338 child[32338]: Sleep seconds 96 parent[32338]: File found parent[32338]: File deleted parent[32338]: Genereated number 46 parent[32338]: File found parent[32338]: File deleted parent[32338]: Genereated number 1 parent[32338]: Running job with pid 32694 parent[32338]: Jobs in queue [1] child[32338]: Job with pid 32338 child[32338]: Sleep seconds 46 parent[32338]: Running job with pid 371 parent[32338]: Jobs in queue [0] child[32338]: Job with pid 32338 child[32338]: Sleep seconds 1 

I hope someone this post will help in the development of bash.

PS: The attentive reader probably saw that there is the same process number everywhere in the log. Since There is no clean fork in bash, here it happens, it can be said to emulate by running the necessary code in () &, which runs it in a separate process, but at the same time keeps the variables unchanged. And we know that the number of the current process in bash is stored in the $$ variable. Therefore, the same process number is displayed in the log file. That is why the start function ends with the line echo $! > $ {PID_FILE}.

Source: https://habr.com/ru/post/151771/


All Articles