I have a bash script (ScreamDaemon.sh) inside which a check that example of it isn\'t running already is added.
numscr=`ps aux | grep ScreamDaemon.s
ps
?This is typical when any constructs which implicitly create a subshell are in play. For instance, in bash:
echo foo | bar
...creates a new forked copy of the shell to run the echo
, with its own ps
instance. Similarly:
( bar; echo done )
...creates a new subshell, has that subshell run the external command bar
, and then has the subshell perform the echo
.
Similarly:
foo=$(bar)
...creates a subshell for the command substitution, runs bar
in there (potentially exec
'ing the command and consuming the subshell, but this is not guaranteed), and reads its output into the parent.
Now, how does this answer your question? Because
result=$(ps aux | grep | wc)
...runs that ps
command in a subshell, which itself creates an extra bash instance.
Use a lockfile.
See for instance:
Note that I strongly suggest use of a flock
-based variant.
Of course, the reason you find an additional process is because:
One process is running the sub-shell (of the command execution `..`
)
included in your line: numscr=`ps aux | grep ScreamDaemon.sh | wc -l`;
that's the simplest answer.
However I would like to make some additional suggestions about your code:
First, quote your expansions, it should be: echo "$str"
.
Not doing so is making several lines collapse into a long one.
Second, you may use: grep [S]creamDaemon.sh
to avoid matching the grep command itself.
Third, capture the command just once in a variable, then count lines from the variable. In this case it presents no problem, but for dynamic processes, one capture and the following capture to count could give different results.
Fourth, make an habit of using $(...)
command substitutions instead of the more error prone (especially when Nesting) `...`
.
### Using a file as the simplest way to capture the output of a command
### that is running in this shell (not a subshell).
ps aux | grep "[S]creamDaemon.sh" > "/tmp/tmpfile$$.txt"
str="$(< "/tmp/tmpfile$$.txt")" ### get the value of var "str"
rm "/tmp/tmpfile$$.txt" ### erase the file used ($$ is pid).
numscr="$(echo "$str" | wc -l)" ### count the number of lines.
echo "$numscr" ### present results.
echo "$str"
str="$( ps aux | grep "[S]creamDaemon.sh" )" ### capture var "str".
numscr="$(echo "$str" | wc -l)" ### count the number of lines.
echo "$numscr" ### present results.
echo "$str"
### The only bashim is the `$(<...)`, change to `$(cat ...)` if needed.
@CharlesDuffy covered the point of a flock
quite well, please read it.