Detect if a tool is already in execution but ONLY for current user
Use pgrep
instead:
pgrep -cxu $USER -f my-tool
The options used are:
-c, --count
Suppress normal output; instead print a count of matching pro‐
cesses. When count does not match anything, e.g. returns zero,
the command will return non-zero value.
-x, --exact
Only match processes whose names (or command line if -f is spec‐
ified) exactly match the pattern.
-u, --euid euid,...
Only match processes whose effective user ID is listed. Either
the numerical or symbolical value may be used.
If you want to use this in a bash script that checks if it is already running, you could use $0
. This expands to the path of the current script (e.g. /home/username/bin/foo.sh
) but we only need foo.sh
. To get that, we can remove everything up to the last /
using bash's string manipulation tools: ${0##*/}
. This means we can do something like:
## If there are more than 1 instances of the current script run
## by this user
if [[ $(pgrep -cxu "$USER" "${0##*/}") -gt 1 ]];
then
echo "Script already running, exiting."
exit
fi
You might also want to consider using lockfiles for this:
## If the lock file exists
if [ -e /tmp/$USER.foo.lock ]; then
## Check if the PID in the lockfile is a running instance
## of foo.sh to guard against crashed scripts
if ps $(cat /tmp/$USER.foo.lock) | grep foo.sh >/dev/null; then
echo "Script foo.sh is already running, exiting"
exit
else
echo "Lockfile contains a stale PID, continuing"
rm /tmp/$USER.foo.lock
fi
fi
## Create the lockfile by printing the script's PID into it
echo $$ > /tmp/$USER.foo.lock
## Rest of the script here
## At the end, delete the lockfile
rm /tmp/$USER.foo.lock
You can use pgrep
fo find if a process is being executed by a specific user and then start the process if not running already by the user:
#!/bin/bash
if pgrep -u "$USER" my-tool &>/dev/null; then
echo 'You already have my-tool running'
else
/path/to/my_tool
fi
The environment variable, $USER
, will be expanded to the currently logged in user i.e. the user running the script. As we are only interested in whether the my-tool
is running or not, so just using the exit status directly with if
construct is enough.
Use this script as a wrapper for starting my-tool
and make the users use this only or rename it as my-tool
and rename the original my-tool
to something else (and change the name inside the script too).
Try it with this snippet:
#!/bin/bash
MyProcessName=$(ps -p $$ -o args=)
Mypid=$$
AllPids=$(pgrep -fu "$(whoami)" "$MyProcessName")
AllPids=$(tr "\n" ' ' <<<"$AllPids")
Pids=$(sed "s/$Mypid//" <<<"$AllPids")
echo "$$: Instances including itself: $AllPids"
echo "$$: Instances different from itself: $Pids"
It is important to not write pgrep|tr
because this would fork into a same named shell.
Wrap the command you wish to run in a flock to ensure that only one copy runs at a time. Use a lock_file stored within a user's home directory tree so that each user has their own lock file. For example:
lockfile = "~/lockfile"
(
if flock -n 200; then
command
else
echo "Could not get lock $lock_file
fi
) 200>$lock_file
'command' can be any bash command or script.
man flock
gives examples of usage