How to stop a bash while loop running in the background?
I started a while loop as follows:
while true; do {command}; sleep 180; done &
Notice the &
.
I thought when I killed the terminal, this while loop would stop. But it is still going. It has been hours since I killed the terminal session.
How do I stop this while loop?
Solution 1:
I started
while true; do yad; sleep 60; done &
and closed the terminal to test it, now I got the same problem.
If you already closed the terminal you've started the loop in
Let's get an overview of running processes with ps fjx
, the last lines on my machine read
2226 11606 11606 19337 ? -1 S 1000 0:00 \_ /bin/bash
11606 22485 11606 19337 ? -1 S 1000 0:00 | \_ sleep 10
2226 9411 9411 8383 ? -1 S 1000 0:00 \_ /bin/bash
9411 17674 9411 8383 ? -1 Sl 1000 0:00 \_ yad
1 2215 2215 2215 ? -1 Ss 1000 0:00 /lib/systemd/systemd --user
2215 2216 2215 2215 ? -1 S 1000 0:00 \_ (sd-pam)
You can see yad
as a subprocess of /bin/bash
, if I close yad
it changes to sleep 60
in the output of ps
. If the tree view is too confusing you can also search the output as follows1:
ps fjx | grep "[y]ad" # or respectively
ps fjx | grep "[s]leep 60"
The output lines begin with two numbers, the first being the PPID, the process ID of the parent process and the second being the PID, the ID of the process itself. It's because of that 9411
appears in both rows here:
2226 9411 9411 8383 ? -1 S 1000 0:00 \_ /bin/bash
9411 17674 9411 8383 ? -1 Sl 1000 0:00 \_ yad
That's the bash
subshell we want to kill and we just found out its PID, so now everything that remains is a simple
kill 9411 # replace 9411 with the PID you found out!
and the annoying subshell is gone for good.
1: The notation as grep "[y]ad"
instead of simply grep yad
prevents the grep
process itself from showing up in the results list.
If you have the terminal still open
bash
provides the variable $!
, which “expands to the process ID of the job most recently placed into the background”, so the following just kills the latest process in the background:
kill $!
If it's not the latest process, just can get a list of running jobs with the jobs
builtin, example output:
[1]- Running while true; do
yad; sleep 60;
done &
[2]+ Stopped sleep 10
There are two jobs in the job list, to kill one of them you can access it with the job number or the shortcuts %
, %+
(“current job”) and %-
(“previous job”), e.g. to kill the loop running in the background you could do
kill %1 # or
kill %-
and to kill the suspended sleep 10
job:
kill %2 # or
kill %+ # or
kill %
Solution 2:
I need to note that when you close the terminal where you entered that command, the sub-command should've died along with it. Trying to reproduce this showed this behavior.
Now, assuming that you indeed are in a situation where this didn't happen, one way to go about killing the program you left running in the background, which was caused by the &
at the end of the command, is as follows:
- Open a new shell and run
echo $$
to note your current PID (process ID), so that you don't kill your own session. - Identify the PID of the program you think is still running; you can do this using the
ps -ef | grep $SHELL
command to find which programs are running a shell. - Note the 2nd column from the left and note the numeric value that differs from your
echo $$
result above; this is the PID you want to kill. - Run the
kill -SIGTERM <pid>
command, where<pid>
is the numeric value you identified in step #3 - Confirm the program is no longer running by repeating step #2
You could also restart your session or your computer, but the above will allow you to avoid that.