4

Suppose I input the following in a shell

(while true; do echo hahaha; sleep 1; done)&

Then I know I can kill it by

fg; CTRL-C

However, if the command above is in a script e.g. tmp.sh and I'm running that script, how to kill it?

Nan Hua
  • 3,414
  • 3
  • 17
  • 24
  • You can kill the last spawned job with kill $! http://stackoverflow.com/questions/1624691/linux-kill-background-task $! is the pid of the last job that was started. – LinuxDisciple Apr 02 '16 at 04:29

2 Answers2

8
(while true; do echo hahaha; sleep 1; done)&
RUNNING_PID=$!
kill ${RUNNING_PID}

$! will pick up the PID of the process that is running so you can do with it as you wish

Michael Ballent
  • 1,078
  • 9
  • 15
  • 2
    He is asking to put all inside a script! You should save the pid in a file. The execution of the script will lead to a new bash process (child of the current bash) in the background. So, every variable executed in the background bash process wouldn't be accessible through the session leader bash. – Facundo Victor Apr 02 '16 at 05:05
  • 1
    I read was how to kill the process that is running in the background that was spawned in a script. Based on that my answer is correct, OP made no mention of having to retain the PID to be run at a later time after the initial spawning of the process was started from a different script. I have written many scripts that spawn many sub processes running in parallel over several machines and wait for them to complete. Why all the complications of writing to disk and then cluttering things up in the file system. – Michael Ballent Apr 02 '16 at 05:37
  • If you put all in the same script, yes, it'll kill itself, almost immediately. But, that is not the idea of @Nan Hua's question. He presented a "while true" script that runs in the background, and ask to determine how to kill it using the session leader shell, because fg; Ctrl+C can't do it. Writing the pid to a file will let you access the pid from any process with permission access to the file. It's not a complication, this is how the daemons writes their pids into a file, to have an ease reference. – Facundo Victor Apr 02 '16 at 06:37
  • BTW -- `RUNNING_PID` shouldn't be all-caps. From http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html: *Environment variable names used by the utilities in the Shell and Utilities volume of POSIX.1-2008 consist solely of uppercase letters, digits, and the underscore [...] and do not begin with a digit. [...] **The name space of environment variable names containing lowercase letters is reserved for applications.** Applications can define any environment variables with names from this name space without modifying the behavior of the standard utilities.* – Charles Duffy Jul 16 '17 at 16:55
  • Which one is right ? pid="" subshell1_background() { back_func & pid=$! } subshell2_background() { { back_func } & pid=$! } subprocess1_background() { (back_func &) pid=$! } subprocess2_background() { (back_func) & pid=$! } – Lewis Chan Dec 14 '18 at 09:09
4

Let's suppose that you have your bash script named tmp.sh with the next content:

#!/bin/bash
(while true; do echo hahaha; sleep 1; done)&

And you execute it! Of course, it will print hahaha to the stdout every 1 second. You can't list it with the jobs command. But... it's still a process! And it's a child in the forest of the current terminal! So:

1- Get the file name of the terminal connected to standard input:

$tty
/dev/pts/2

2- List the processes associated with the terminal (In the example we are using pts/2), and show the status with S and display in a forest format f:

$ps --tty pts/2 Sf
PID TTY      STAT   TIME COMMAND
3691 pts/2    Ss+    0:00 /bin/bash
3787 pts/2    S      0:00 /bin/bash
4879 pts/2    S      0:00  \_ sleep 1

3- Now, you can see that the example lists a sleep 1 command that is a child of the /bin/bash process with PID 3787. Now kill it!

kill -9 3787

Note: Don't kill the bash process that has the s+ statuses, is bash process that gives you the prompt! From man(ps):

s    is a session leader
+    is in the foreground process group

Recommendations:

In a case like this, you should save the PID in a file:

#!/bin/bash
(while true; do echo hahaha; sleep 1; done)&
echo $! > /path/to/my_script.pid

Then, you could just do some script to shut it down:

#!/bin/bash
kill -9 $(cat /path/to/my_script.pid)
Facundo Victor
  • 3,308
  • 1
  • 25
  • 20
  • Why should the PID be saved in a file? – Akito Feb 04 '20 at 02:02
  • To be able to refer it easily from outside the script. This is what all daemons do under `/var/run/.pid` – Facundo Victor Feb 05 '20 at 11:38
  • Thanks for the info. I wanted to make sure that the file is not absolutely necessary. I created a script without writing to a file and it works fine within the script itself, so the file is only necessary for the case you mentioned. – Akito Feb 05 '20 at 12:37