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?
4
  • 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. Commented Aug 30, 2021 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. Commented Aug 30, 2021 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. Commented Aug 30, 2021 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 :) Commented Aug 30, 2021 at 15:55

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

But echo $(pgrep ...) still only outputs a single process ID.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.