Different results between ps aux and `ps aux` inside a script

前端 未结 2 1041
抹茶落季
抹茶落季 2020-12-20 05:22

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         


        
相关标签:
2条回答
  • 2020-12-20 06:03

    Why can a single bash script show up multiple times in 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.


    How can I properly ensure that only one copy of my script is running?

    Use a lockfile.

    See for instance:

    • How to prevent a script from running simultaneously?
    • What is the best way to ensure only one instance of a Bash script is running?

    Note that I strongly suggest use of a flock-based variant.

    0 讨论(0)
  • 2020-12-20 06:21

    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.

    0 讨论(0)
提交回复
热议问题