0

I'm trying to make sure my script only runs once at a time, but im running into weird behavior with inverting grep.

My Code:

echo "Current Pid: $$"
# Output "Current Pid: 5387"
echo "Process Count: $(pgrep -c -f "$0")"
# Output: Process Count: 2

if [ "$(pgrep -c -f "$0")" -gt 1 ]
then
    echo All Pids
    pgrep -f "$0"
    # Output "4978, 5387"

    echo Pids Current
    echo "$(pgrep -f "$0" |& grep -F $$)"
    # Output "5387"

    echo Pids Inverted
    echo "$(pgrep -f "$0" |& grep -Fv $$)"
    # Output "4978, 5394"

    # processPidsToKill="$(pgrep -f "$0" |& grep -Fv $$)"

    # for processPid in $processPidsToKill; do
    #     echo "Killing `basename "$0"` $processPid"
    #     kill "$processPid"
    # done
fi

Can someone tell me what im doing wrong? Where does the new Pid come from when im using "grep -v"?

Cyrus
  • 84,225
  • 14
  • 89
  • 153
PandaSITT
  • 37
  • 6
  • Does this happen every time you run the script? – Barmar Apr 15 '22 at 19:16
  • Because I'm thinking that another instance of the script might have started up between the commands. – Barmar Apr 15 '22 at 19:19
  • Did you try doing `ps -p 5394` to see what's running there? – Barmar Apr 15 '22 at 19:24
  • @Barmar yes, and just to be sure i tried it on a different system and got the same result. I dont think a new instand started, since i made a new script and started it twice my self. Also the new Pid sometimes no longer existed when it tried to kill it. – PandaSITT Apr 15 '22 at 19:28
  • Keep in mind that `$$` gives you only the PID of the parent shell, not that of any subshell. – Charles Duffy Apr 15 '22 at 19:31
  • @CharlesDuffy Why would that matter here? The current shell (running this script) is what they want to exclude. – Barmar Apr 15 '22 at 19:32
  • @Barmar, they've got a command substitution with a pipeline in it. `$BASHPID` is going to be different from `$$` – Charles Duffy Apr 15 '22 at 19:32
  • @CharlesDuffy `$$` inside a command substitution is the original shell, not the subshell. – Barmar Apr 15 '22 at 19:33
  • Yes, that's my point. The pipeline is still running when all this happens. – Charles Duffy Apr 15 '22 at 19:33
  • 2
    @CharlesDuffy Oh, I see. `pgrep` excludes itself, but it doesn't exclude the subshell created to exexute the `$(...)`, which has the same name as the original shell. I guess you should write that as an answer. – Barmar Apr 15 '22 at 19:35
  • 1
    I'm not comfortable bringing that up to the level of an answer without some testing I don't have time to do right now (Q: does `grep -Ev "^($$|$BASHPID)\$"` suffice, or does that still leave the other pipeline component's subshell unhandled?), but yes, that's an accurate statement of my theory of the problem. – Charles Duffy Apr 15 '22 at 19:37
  • 1
    @PandaSITT, ...to be clear, in general, I consider any use of pgrep a code smell / indication that someone is doing something wrong. If you're doing process supervision correctly it tends to be generally unnecessary because you can just tell systemd to kill the whole cgroup for your service (or equivalent in whatever other framework you're using). – Charles Duffy Apr 15 '22 at 19:38
  • 1
    @PandaSITT, ...when that's not an option for whatever reason I typically use a file handle to tag processes that might need to be selected and killed -- `exec {lockfile_fd}>/path/to/tempfile` before starting your background process, and then `fuser -k /path/to/tempfile` to kill every process with a handle on that file; much more reliable than going by name, and it lets you have multiple sets of processes and address them individually as long as each one uses a different lockfile. – Charles Duffy Apr 15 '22 at 19:41
  • @CharlesDuffy Its more then possible that im doing something wrong, i never really used Bash Script before. Im guessing the new Pid is a Subprocess ever grep or pgrep. Its done running imideatlly after that line of code. – PandaSITT Apr 15 '22 at 19:46
  • Thanks for the help, scrapping my code and im following [this](https://wiki.bash-hackers.org/howto/mutex) guid – PandaSITT Apr 15 '22 at 20:01
  • 2
    Nothing wrong with that guide (in general, the bash-hackers' wiki is a great resource), but if you're only targeting Linux you might think about using `fuser` (which is mentioned there, but not demonstrated). The answer on this site to [Linux flock: How to "just" lock a file?](https://stackoverflow.com/questions/24388009/linux-flock-how-to-just-lock-a-file) is a little on the complicated side as demonstrations go (given that the OP there asked for something that was deceptively complicated); for something simpler, you might just look at the usage pattern shown in `man flock`. – Charles Duffy Apr 15 '22 at 20:16

0 Answers0