1
for i in $( seq 1 $1 )
do
        kill %$i
done

I try to kill the stopped jobs with this script, but interestingly it can't be able to even though I have jobs open.

$ jobs
[10]   Stopped                 vim detect_thread.py
[11]   Stopped                 python3 detect.py
[12]-  Stopped                 python3 detect.py
[13]+  Stopped                 python3 detect.py
$ kill 13
bash: kill: (13) - No such process
$ ./delete.sh 13
./delete.sh: line 8: kill: %1: no such job
./delete.sh: line 8: kill: %2: no such job
./delete.sh: line 8: kill: %3: no such job
./delete.sh: line 8: kill: %4: no such job
./delete.sh: line 8: kill: %5: no such job
./delete.sh: line 8: kill: %6: no such job
./delete.sh: line 8: kill: %7: no such job
./delete.sh: line 8: kill: %8: no such job
./delete.sh: line 8: kill: %9: no such job
./delete.sh: line 8: kill: %10: no such job
./delete.sh: line 8: kill: %11: no such job
./delete.sh: line 8: kill: %12: no such job
./delete.sh: line 8: kill: %13: no such job

2 Answers2

2

The kill builtin only recognizes the %N format for jobs running in the current shell. However, shell scripts run in their own separate subshell and in that subshell, there are no jobs to kill. This might be clearer with an example:

$ for i in {1..5}; do sleep 100 & done
[1] 2259152
[2] 2259153
[3] 2259154
[4] 2259155
[5] 2259156
$ for i in {1..5}; do kill %$i; done
[1]   Terminated              sleep 100
[2]   Terminated              sleep 100
[3]   Terminated              sleep 100
[4]-  Terminated              sleep 100
[5]+  Terminated              sleep 100

As you can see, that works as expected if you run both sets of commands in the same shell session. Similarly, it also works if you launch and kill the commands from the same shell script:

#! /usr/bin/env bash
for i in {1..5}; do
  sleep 100 &
done

Show the running jobs

runningSleepJobs=$(pgrep -c sleep) echo "There are $runningSleepJobs sleep jobs running!"

for i in {1..5}; do kill %$i; done

Show that they've been stopped

runningSleepJobs=$(pgrep -c sleep) echo "Now there are $runningSleepJobs sleep jobs running!"

If I now run this script, I can see it both starts and then kills the jobs as expected:

$ foo.sh
There are 5 sleep jobs running!
Now there are 0 sleep jobs running!

There is a way around this, however. Instead of executing your script, you can source it so that it runs in the current shell:

$ cat ~/bin/foo.sh
#! /usr/bin/env bash
for i in $( seq 1 $1 )
do
        kill %$i
done

$ for i in {1..5}; do sleep 100 & done [1] 2295221 [2] 2295222 [3] 2295223 [4] 2295224 [5] 2295225

$ jobs [1] Running sleep 100 & [2] Running sleep 100 & [3] Running sleep 100 & [4]- Running sleep 100 & [5]+ Running sleep 100 &

$ . ~/scripts/foo.sh 5 [1] Terminated sleep 100 [2] Terminated sleep 100 [3] Terminated sleep 100 [4]- Terminated sleep 100 [5]+ Terminated sleep 100

terdon
  • 242,166
1

A shell script will run with its own environment, which means the job management will not know about the job roster of the shell from which the script is executed. Use . to run the script in your current environment:

$ . ./delete.sh 13
DopeGhoti
  • 76,081