Check if PID exists in Bash - bash

I want to stall the execution of my BASH script until a process is closed (I have the PID stored in a variable). I'm thinking
while [PID IS RUNNING]; do
sleep 500
done
Most of the examples I have seen use /dev/null which seems to require root. Is there a way to do this without requiring root?
Thank you very much in advance!

kill -s 0 $pid will return success if $pid is running, failure otherwise, without actually sending a signal to the process, so you can use that in your if statement directly.
wait $pid will wait on that process, replacing your whole loop.

It seems like you want
wait $pid
which will return when $pid finishes.
Otherwise you can use
ps -p $pid
to check if the process is still alive (this is more effective than kill -0 $pid because it will work even if you don't own the pid).

You might look for the presence of /proc/YOUR_PID directory.

ps --pid $pid &>/dev/null
returns 0 if it exists, 1 otherwise

I always use the following
tail -f /dev/null --pid $PID. It doesn't require explicit loop and isn't limited to your shell's children pids only.

Related

Wait for last created process (daemon which forks) to end

I'm writing a wrapper script to use in inittab.
This script starts a daemon and waits for it to terminate.
Here's what I have currently:
#!/bin/bash
/usr/local/bin/mydaemon --lots_of_params_here
while kill -0 `echo $!` 2> /dev/null; do sleep 1; done;
The problem is with the second line; it just returns immediately. If I instead do:
while kill -0 `pgrep mydaemon` 2> /dev/null; do sleep 1; done;
It all works fine, but this isn't a good solution for me as I have other scripts with the prefix mydaemon.
What am I doing wrong?
EDIT:
The problem seems to be related to the daemon fork(). So, I always get the parent pid in $!. I'm looking for ways to solve this problem. Maybe I should use pid files and have mydaemon write its pid there.
You can do the following way to get through your issue.
#!/bin/bash
/usr/local/bin/mydaemon --lots_of_params_here &
wait $!
wait command will wait till the process completes and comes out.
If you are looking for to wait after some other commands then you can store the PID in any other variable and use that.
#!/bin/bash
/usr/local/bin/mydaemon --lots_of_params_here &
mypid=$!
### Some other commands
wait $mypid

Wait for process to finish, or user input

I have a backgrounded process that I would like to wait for (in case it fails or dies), unless I receive user input. Said another way, the user input should interrupt my waiting.
Here's a simplified snippet of my code
#!/bin/bash
...
mplayer -noconsolecontrols "$media_url" &
sleep 10 # enough time for it to fail
ps -p $!
if [ $? -ne 0 ]
then
fallback
else
read
kill $!
fi
The line that I particularly dislike is sleep 10, which is bad because it could be too much time, or not enough time.
Is there a way to wait $! || read or the equivalent?
Use kill -0 to validate that the process is still there and read with a timeout of 0 to test for user input. Something like this?
pid=$!
while kill -0 $pid; do
read -t 0 && exit
sleep 1
done
Original
ps -p to check the process. read -t 1 to wait for user input.
pid=$!
got_input=142
while ps -p $pid > /dev/null; do
if read -t 1; then
got_input=$?
kill $pid
fi
done
This allows for branching based whether the process died, or was killed due to user input.
All credit to gubblebozer. The only reason I'm posting this answer is the claim by moderators that my edits to his post constituted altering his intent.
Anti Race-Condition
First off, a race condition involving pids is (very likely) not a concern if you're fairly quick, because they're reused on a cycle.
Even so, I guess anything is possible... Here's some code that handles that possibility, without breaking your head on traps.
got_input=142
while true; do
if read -t 1; then
got_input=$?
pkill --ns $$ name > /dev/null
break
elif ! pgrep --ns $$ name > /dev/null; then
break
fi
done
Now, we've accomplished our goal, while (probably) completely eliminating the race condition.
Any loop with a sleep or similar timeout in it, will introduce a race condition. It's better to actively wait for the process to die, or, in this case, to trap the signal that's sent when a child dies.
#!/bin/bash
set -o monitor
trap stop_process SIGCHLD
stop_process()
{
echo sigchld received
exit
}
# the background process: (this simulates a process that exits after 10 seconds)
sleep 10 &
procpid=$!
echo pid of process: $procpid
echo -n hit enter:
read
# not reached when SIGCHLD is received
echo killing pid $procpid
kill $procpid
I'm not 100% sure this eliminates any race condition, but it's a lot closer than a sleep loop.
edit: the shorter, less verbose version
#!/bin/bash
set -o monitor
trap exit SIGCHLD
sleep 5 &
read -p "hit enter: "
kill $!
edit 2: setting the trap before starting the background process prevents another race condition in which the process would die before the trap was installed

Checking and killing hanged background processes in a bash script

Say I have this pseudocode in bash
#!/bin/bash
things
for i in {1..3}
do
nohup someScript[i] &
done
wait
for i in {4..6}
do
nohup someScript[i] &
done
wait
otherThings
and say this someScript[i] sometimes end up hanging.
Is there a way I can take the process IDs (with $!)
and check periodically if the process is taking more than a specified amount of time after which I want to kill the hanged processes with kill -9 ?
Unfortunately the answer from #Eugeniu did not work for me, timeout gave an error.
However I found useful doing this routine, I'll post it here so anyone can take advantage of it if in my same problem.
Create another script which goes like this
#!/bin/bash
#monitor.sh
pid=$1
counter=10
while ps -p $pid > /dev/null
do
if [[ $counter -eq 0 ]] ; then
kill -9 $pid
#if it's still there then kill it
fi
counter=$((counter-1))
sleep 1
done
then in the main work you just put
things
for i in {1..3}
do
nohup someScript[i] &
./monitor.sh $! &
done
wait
In this way for any of your someScript you will have a parallel process that checks if it's still there every chosen interval (until maximum time decided by the counter) and that actually quit itself if the associated process dies (or gets killed)
One possible approach:
#!/bin/bash
# things
mypids=()
for i in {1..3}; do
# launch the script with timeout (3600s)
timeout 3600 nohup someScript[i] &
mypids[i]=$! # store the PID
done
wait "${mypids[#]}"

Using while or until to wait until a PID doesn't exist

I have been using Bash to wait until a PID no longer exists. I've tried
#!/bin/bash
while [ kill -0 PID > /dev/null 2>&1 ]; do
//code to kill process
done
//code to execute after process is dead
as well as
#!/bin/bash
until [ ! kill -0 PID > /dev/null 2>&1 ]; do
//code to kill process
done
//code to execute after process is dead
Both these examples either fail to work, or keep on looping after the process has ended. What am I doing incorrectly?
You should be simply doing:
while kill -0 $PID >/dev/null 2>&1
do
# Code to kill process
done
The loop condition tests the exit status of the last command — in this case, kill. The -0 option (used in the question) doesn't actually send any signal to the process, but it does check whether a signal could be sent — and it can't be sent if the process no longer exists.
(See the POSIX specification of the kill() function and the POSIX kill utility.)
The significance of 'last' is that you could write:
while sleep 1
echo Testing again
kill -0 $PID >/dev/null 2>&1
do
# Code to kill process
done
This too tests the exit status of kill (and kill alone).
Also you can do in unixes with procfs (almost all except mac os)
while test -d /proc/$PID; do
kill -$SIGNAL $PID
# optionally
sleep 0.2
done

What does `kill -0 $pid` in a shell script do?

Basically, what signal does '0' represent, because here I see SIGNAL numbers starting from 1.
sending the signal 0 to a given PID just checks if any process with the given PID is running and you have the permission to send a signal to it.
For more information see the following manpages:
kill(1)
$ man 1 kill
...
If sig is 0, then no signal is sent, but error checking is still performed.
...
kill(2)
$ man 2 kill
...
If sig is 0, then no signal is sent, but error checking is still performed; this
can be used to check for the existence of a process ID or process group ID.
...
This is a Good Question Because...
...it can be hard to find documentation on this special signal. Despite what others have said, the only mention of this signal in man 1 kill in Debian-based systems is:
Particularly useful signals include HUP, INT, KILL, STOP, CONT, and 0.
Not especially helpful, especially if you don't already know what the signal does. It is also not listed by the output of kill -l, so you won't know about it unless you already know about it.
Where to Find It Documented
On Debian and Ubuntu systems, the output of man 2 kill says, in part:
If sig is 0, then no signal is sent, but error checking is still performed; this can be used to check for the existence of a process ID or process group ID.
What It's Good For
You can use kill -0 to check whether a process is running. Consider these examples.
# Kill the process if it exists and accepts signals from
# the current user.
sleep 60 &
pid=$!
kill -0 $pid && kill $pid
# Check if a PID exists. When missing, this should result
# in output similar to:
# bash: kill: (6228) - No such process
# Exit status: 1
kill -0 $pid; echo "Exit status: $?"
You can also use kill -0 to determine if the current user has permissions to signal a given process. For example:
# See if you have permission to signal the process. If not,
# this should result in output similar to:
# bash: kill: (15764) - Operation not permitted
# Exit status: 1
sudo sleep 60 &
kill -0 $!; echo "Exit status: $?"
kill -0 $pid is to check whether the process with process id (pid) exists or not.
Be careful while using kill -0 $pid to check the process existence because
Once the intended process exit then its pid can be allot to other newly created process. ( So one can not be so sure that particular process is alive or not )
In case of zombie process, for which child is waiting for parent to call wait. Here it hold the $pid and give the positive result while that process is not running.
This command checks wether the process with PID in $pid is alive.
Sending the EXIT signal, or 0 to a process will:
Check for the existence of a process.
Do various error checking on the process (PID, PGID, etc ...).
It will not send any output to stdout upon success.
Send an error message to stderr if something is not right.
Give you a false positive if the process is defunct (i.e. Zombie).
More explicitly, a useful function for your shell scripts would be:
function isProcess ()
{
kill -s EXIT $1 2> /dev/null
}
This returns no text to stdout upon success, but an error message to stderr upon failure (but I have redirected that error message to /dev/null).
If you are concerned about defunct / zombie process status, then you need to use ps, preferably with the --no-headers switch.
#!/bin/ksh
function trim ()
{
echo -n "$1" | tr -d [:space:]
}
function getProcessStatus ()
{
trim $(ps -p $1 -o stat --no-headers)
}
function isZombie ()
{
typeset processStatus=$(getProcessStatus $1)
[[ "$processStatus" == "Z" ]]
return $?
}
kill -0 $pid is used to check if a process running with $pid is alive or not. But this can be tricky, as process ID can be reassigned, once a process exit and new process runs.
One can use killall -0 <process name> to get about a particular process is running or not.

Resources