1

I created a script to verify if a scheduled process is already running and in that case I block the execution showing a message "script is already running". The problem is that I inserted these lines of code

scriptToVerify="send_xxxx.sh ${1} ${2}";
num_proc=`ps auxww | grep "$scriptToVerify" | grep -v $$ | grep -v grep | awk /./ | /usr/bin/wc -l`;

if [ $num_proc -gt 1 ];
then
    sl_log "---------------------------Warning---------------------------"
    sl_log "$scriptToVerify Already running"
    exit 0;
fi

in a large number of scripts (every script is scheduled, sometimes at the same time). I have tried different solutions: using a flock instruction, using a lockfile, but everytime (even the instructions I wrote above) my code works for a few weeks and then starts to report a "script already running" also it isn't true.

Unfortunately I can't manage the scheduler, so how can I modify my script in order to verify if a process is actually running?

Matteo
  • 316
  • 1
  • 7
  • 21
  • Have a look here... https://stackoverflow.com/a/37303133/2836621 – Mark Setchell Jul 25 '19 at 09:10
  • 2
    I don't think "grep -v $$" is good idea. what happens when the script is running in pid = 12. and the script to verify is runnig in pid = 1234 ? – ymonad Jul 25 '19 at 09:11
  • @MarkSetchell I already did it. Is one of the first thread I've seen – Matteo Jul 25 '19 at 09:15
  • What are the parameters `$1` and `$2`? Could they contain any special symbols like `*`, `+`, `?`, `.` which would then be interpreted by grep and could lead to false matches? – Socowi Jul 25 '19 at 10:14
  • @Socowi no, they are two parameters and they are string or int – Matteo Jul 25 '19 at 12:08
  • A string can contain the symbol `*`. Or did you mean both of these parameters can only assume the literal values "`string`" and "`int`"? The latter would be very strange. – Socowi Jul 25 '19 at 12:24
  • @Socowi no, they are defined like this: /folder1/folder2/folder3/script.sh icbp 8 – Matteo Jul 25 '19 at 13:20

1 Answers1

1

Using ps ... | grep ... | grep -v ... | grep -v grep | ... to match process by its name (or command line) is fraught with problems (like the $$ matching also part of PID as mentioned in one of the comments), using pgrep(1) in this case should be much easier and give you just what you need.

You do not have to worry about its output either (even though it can -c count matches) and instead just use the fact it'll return 0 if anything matched and 1 otherwise. Use -f in this case to match against the full command line and not just process name.

if pgrep -f "${scriptToVerify}" >/dev/null; then
    echo "'${scriptToVerify}' already running"
fi

You can also make it a bit more verbose if you still got accidental unwanted matches (note: some process could get terminated between call to pgrep and ps that follows):

matched_pids=$(pgrep -f "${scriptToVerify}")
if [[ -n "${matched_pids}" ]]; then
    echo "Already running:"
    ps -o pid,cmd -p ${matched_pids}
fi

You can also make sure pattern does not accidentally match unwanted strings (processes), and for instance use pgrep -f "${scriptToVerify}\$" of not other arguments follow or even pgrep -f "^${scriptToVerify}\$" if scriptToVerify is a complete match, or pgrep -f "(^|\\<)${scriptToVerify}\$" perhaps the value starting with script basename and all the arguments are expected to be a match.

Ondrej K.
  • 8,841
  • 11
  • 24
  • 39
  • Ideally you would also use `pgrep`'s `-x` option and quote special symbols like `*` inside the variable `scriptToVerify`. – Socowi Jul 25 '19 at 12:25