1

Sorry for my poor english ;)

I need to check if a script is already running or not. I don't want to use a lock file, as it can be tricky (ie: if my script wrote a lock file, but crashed, I will consider it as running). I also need to take parameters into account. ie: test.sh 123 should be considered as a different process than test.sh 456

I tried this :

#!/bin/bash

echo "inside test.sh, script name with arguments: $0 +$*$"

echo "  simple pgrep on script name with arguments:"
pgrep -f "$0 +$*$"

echo "  counting simple pgrep on script name with arguments with wc -l"
echo $(pgrep -f "$0 +$*$" | wc -l)

echo "  counting pgrep echo result with wc -w"
processes=$(pgrep -f "$0 +$*$")
nbProcesses=$(echo $processes | wc -w)
echo $nbProcesses

sleep 300

When I try, I get this result:

[frederic.charrier@charrier tmp]$ /tmp/test.sh 123
inside test.sh, script name with arguments: /tmp/test.sh +123$
  simple pgrep on script name with arguments:
123976
  counting simple pgrep on script name with arguments with wc -l
2
  counting pgrep echo result with wc -w
1
^Z
[1]+  Stoppé                 /tmp/test.sh 123
[frederic.charrier@charrier tmp]$ /tmp/test.sh 123
inside test.sh, script name with arguments: /tmp/test.sh +123$
  simple pgrep on script name with arguments:
123976
124029
  counting simple pgrep on script name with arguments with wc -l
3
  counting pgrep echo result with wc -w
2

My questions are:

  • when I run the script the first time, it's running once. So pgrep is returning only one result: 123976, which is fine. But why a "wc -l" on 123976 is returning 2?
  • when I run the script a second time, I get the same strange behavior: pgrep returns the correct result, pgrep | wc -l returns something wrong, and "echo pgrep ... | wc -w" returns the correct result. Why?
  • Is it possible the pgrep command is finding itself in addition to the command you're looking for? You can check by using `ps` and you can avoid it by using `| grep -v grep` to exclude the PIDs from grep commands. – user1717259 Aug 30 '21 at 14:21
  • This seems to be specific to Linux, by the way. I cannot reproduce on macOS. Whether the issue is with `pgrep` or `wc`, I cannot tell. – chepner Aug 30 '21 at 14:25
  • If you can't find the solution you are looking for in the 54 answers in the two linked questions, please explain why and your question can be considered for reopening. – David C. Rankin Aug 30 '21 at 14:55
  • Sorry if it sounds as duplicated, but I wanted to avoid a "flock" solution. Anyway, everything is fine, as @kamilcuk answer helped me to understand the "two processes" count after a substitution :) – Frédéric Charrier Aug 30 '21 at 15:55

1 Answers1

1

How to detect if a bash script is already running

If you are aware of the drawbacks of your method, using pgrep looks fine. Note that both $0 and $* can have regex-syntax stuff in them, you have to escape them first, and I think I would also do pgrep -f "^$0... to match it from the beginning.

why a "wc -l" on 123976 is returning 2?

Because command substitution $(..) spawns a subshell, so there are two shells running, when pgrep is executed.

Overall, echo $(cmd) is an antipattern. Just run it cmd.

In some cases, like when there is single one command inside command substitution, bash optimizes and replaces (exec) the subshell with the command itself, effectively eliminating the subshell. This is an optimization. That's why processes=$(pgrep ..) returns 1.

Why?

There is one more process running.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111