Bash script iterate over PID's and kill items - linux

I try to kill all occurrences of a process, what's happen actually an iteration stops after first item, what's wrong here ?
#!/usr/bin/env bash
SUPERVISORCLS=($(pidof supervisorctl))
for i in "${SUPERVISORCLS[#]}"
do
echo $i
exec sudo kill -9 ${i}
done
Before I tried sth like this as solution for restart script, but as well script was not always executed at total always only one if block was executed.?
ERROR0=$(sudo supervisord -c /etc/supervisor/supervisord.conf 2>&1)
if [ "$ERROR0" ];then
exec sudo pkill supervisord
exec sudo supervisord -c /etc/supervisor/supervisord.conf
echo restarted supervisord
fi
ERROR1=$(sudo supervisord -c /etc/supervisor/supervisord.conf 2>&1)
if [ "$ERROR1" ];then
exec sudo pkill -9 supervisorctl
exec sudo supervisorctl -c /etc/supervisor/supervisord.conf
echo restarted supervisorctl
fi

exec replaces your process with the executable that's the argument to it, so you will never execute another statement in your script after it hits an exec. Your process will no longer exist. In the first example your process will no longer be your script it will be kill and pkill in the second.
To fix it, just remove exec from all those lines. It's not needed. When executing a script the shell will execute the commands on every line already, you don't have to tell it to do so.

Related

finding the process group id created through setsid

In a shell script, I see that using setsid, we could create a new process group. I am not able to find a reliable way to get the group id after the creation. My requirement is simple, launch a process, and after it is done, clean up any descendant (if any). I dont want to kill the main process, hence I have to wait for the main process to end. After which, I can kill the leftover child processes if I had somehow got the group id. which can be done with kill -- -pgid. The missing piece is how do I get the group id ?
This script is what I came up with finally. Hope this helps someone.
$! will give the pid, and a ps has to be used to find its gid.
there was an extra space in front while using ps,the next line of variable expansion removes the leading space.
Finally after waiting for the main process,it kills the group.
#!/bin/sh -x
setsid "$#" &
pid=$!
gidspace=$(ps -o pgid= $pid)
gid="${gidspace## }"
echo "gid $gid"
echo "waiting"
wait $pid
ps -s $gid -o pid,ppid,pgid,command
kill -- -$gid
I managed to do it with a coproc, and a sleep to ensure we have enough time to read back the pid. This is bash-specific of course, and the only way to avoid using a hackish sleep inside a coproc is to write to a temp file and wait for the command to terminate (no need for coproc then).
Using a coproc
Note that I open filehandle 3 to write the pgid back to the parent shell and close it before executing the command.
#!/bin/bash -x
coproc setsid bash -c 'ps -o pgid= $BASHPID >&3; exec 3>&-; exec "$#" & sleep 1' -- "$#" 3>&1
read -u ${COPROC[0]} gid
echo "gid $gid"
ps -s $gid -o pid,ppid,pgid,command
kill -- -$gid
Using a temp file
To avoid having to pass the temp file to the subshell (and the risk the parent dies and removes it before child writes to it) I again open fh 3 so the children can write its pgid to it.
#!/bin/bash -x
t=$(mktemp)
trap 'rm -f "$t"' EXIT
exec {fh}>"$t"
setsid bash -c 'ps -o pgid= $BASHPID >&3; exec 3>&-; exec "$#" &' -- "$#" 3>&${fh}
read gid <$t
echo "gid $gid"
ps -s $gid -o pid,ppid,pgid,command
kill -- -$gid

How to kill a process by reading from pid file using bash script in Jenkins?

Inside Jenkins, I have to run 2 separate scripts: start.sh and stop.sh. These scripts are inside my application which is fetched from a SCM . They are inside same directory.
The start.sh script runs a process in the background using nohup, and writes the processId to save_pid.pid. This script works fine. It successfully starts my application.
Then inside stop.sh, I am trying to read the processId from save_pid.pid to delete the process. But,I am unable to delete the process and the application keeps running until I kill the process manually using: sudo kill {processId}.
Here are the approaches that I have tried so far inside stop.sh but none of these work:
kill $(cat /path/to/save_pid.pid)
kill `cat /path/to/save_pid.pid`
kill -9 $(cat /path/to/save_pid.pid)
kill -9 `cat /path/to/save_pid.pid`
pkill -F /path/to/save_pid.pid
I have also tried all of these steps with sudo as well. But, it just doesn't work. I have kept an echo statement inside stop.sh, which prints and then there is nothing.
What am I doing wrong here ?
UPDATE:
The nohup command that I am using inside start.sh is something like this:
nohup deploy_script > $WORKSPACE/app.log 2>&1 & echo $! > $WORKSPACE/save_pid.pid
Please Note:
In my case, the value written inside save_pid.pid is surprisingly
always less by 1 than the value of actual processId. !!!
I think the reason why this happens is because you are not getting the PID of the process that you are interested in, but the PID of the shell executing your command.
Look:
$ echo "/bin/sleep 10" > /tmp/foo
$ chmod +x /tmp/foo
$ nohup /tmp/foo & echo $!
[1] 26787
26787
nohup: ignoring input and appending output to 'nohup.out'
$ pgrep sleep
26789
So 'nohup' will exec the 'shell', the 'shell' will fork a second 'shell' to exec 'sleep' in, however I can only count two processes here, so I am unable to account for one created PID.
Note that, if you put the nohup and the pgrep on one line, then pgrep will apparently be started faster than the shell that 'exec's 'sleep' and thus pgrep will yield nothing, which somewhat confirms my theory:
$ nohup /tmp/foo & echo $! ; pgrep sleep
[2] 26899
nohup: ignoring input and appending output to 'nohup.out'
$
If you launch your process directly, then nohup will "exec" your process and thus keep the same PID for the process as nohup itself had (see http://sources.debian.net/src/coreutils/8.23-4/src/nohup.c/#L225):
$ nohup /bin/sleep 10 & echo "$!"; pgrep sleep
[1] 27130
27130
nohup: ignoring input and appending output to 'nohup.out'
27130
Also, if you 'exec' 'sleep' inside the script, then there's only one process that's created (as expected):
$ echo "exec /bin/sleep 10" > /tmp/foo
$ nohup /tmp/foo & echo "$!"; pgrep sleep
[1] 27309
27309
nohup: ignoring input and appending output to 'nohup.out'
27309
Thus, according to my theory, if you'd 'exec' your process inside the script, then you'd be getting the correct PID.

Bash calls two bash scripts

I have the following script:
#!/bin/bash
if [ "$EUID" -ne 0 ]
then
echo ''
echo 'Please run the script as root'
echo ''
exit
fi
for run in {1..11}
do
sudo ./start_ap.sh
sleep 10
sudo ./tst.sh
done
The problem is that after executing
sudo ./start_ap.sh
the next lines will not be executed, because the line sudo ./start_ap.sh needs CTRL+C to stop and only then next lines will be executed.
However, I want that the sudo ./start_ap.sh will be terminated after sudo ./tst.sh and at next step this will be repeated 11 times.
So far, after execution of sudo ./start_ap.sh, the next lines will not be executed without killing its process.
How can I realize it?
P.S. start_ap.sh starts the hostapd and that's why it needs killing for next executions.
You need to run ./start_ap.sh in the background, then kill it after ./tst.sh completes. Note that if you actually run the script as root, there is no need to use sudo inside the script.
for run in {1..11}; do
./start_ap.sh & pid=$!
sleep 10
./tst.sh
kill "$pid"
done

script to check script is running and start it, if it’s stopped

I have a script with this name : Run.sh
I run this script with this command :
./run.sh
I don't like stop this script but this script Suddenly stops and need run again.
I need a script to check it , if my run.sh stopped , run it again.
this is run.sh codes:
#!/usr/bin/env bash
install() {
sudo apt-get update
sudo apt-get upgrade
}
if [ "$1" = "install" ]; then
install
else
if [ ! -f ./tg/tgcli ]; then
echo "tg not found"
echo "Run $0 install"
exit 1
fi
#sudo service redis-server restart
#./tg/tgcli -s ./bot/bot.lua -l 1 -E $#
./tg/tgcli -s ./bot/bot.lua $#
fi
And i want run this script at boot (with screen or tmux) if my server restart
i have Ubuntu 16.04 version
Thank you Ljm Dullaart
Can you help me about this ?
You should not need to run the complete bash script again. Changing
./tg/tgcli -s ./bot/bot.lua $#
to
while :; do
./tg/tgcli -s ./bot/bot.lua $#
done
will restart bot.lua everytime it exits.
You can check if your run.sh is running and re-run it if stopped with a single command:
$ if ! pgrep run.sh ;then /path/to/run.sh;fi
If script runs pgrep will return exit status 0 = success and will print the pid of run.sh
If script does not run pgrep will return exit status 1 and then script will be called.
You can also use pgrep inst.sh >/dev/null to "mute" pgrep in case script is running.

How to run a pkill when invoking a shell to execute a string of commands?

To automate a system administration task, I wrote down the following line of shell code:
bash -c 'pkill -TERM -f java; true'
The problem is that pkill kills the bash immediately after the pkill command executes, and therefore subsequent commands do not have a chance to execute.
Apart from splitting the them into two lines:
bash -c 'pkill -TERM -f java'
bash -c 'true'
Is there any other workaround?
If you want to kill all java processes, simply drop the -f:
bash -c 'pkill -TERM java; true'
If you really also want to kill non-java processes like mplayer "jungle_gremlins_of_java.avi", the typical "solution" is to rewrite the command so that the pattern doesn't match itself:
bash -c 'pkill -TERM -f "[j]ava"; true'

Resources