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

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.

Related

Running a interactive command as a background process in shell script

I am facing an issue when I am trying to run a interactive command/app in the background of the shell script. I am trying to log the output of the command to a file. But I don't see that command logging anything to the file. Even executing the command in the bash also did not work as it gets suspended.
Sample script
#!/bin/bash
while true
do
./a.out > test &
PID=$!
sleep 20
kill -9 $PID
done
[#myprog]$ ./a.out &
[1] 3275
Program started
[1]+ Stopped ./a.out
[#myprog]$
You don't need to create a background process to redirect data. You can do the following, which will create a logfile actions.log which holds your every action.
#! /bin/bash
while read -p "action " act; do
echo $act
done > actions.log
exit 0
For you, this would be something like:
$ a.out > test.log
If you do want to have a background process, but need to input data:
$ function inter_child {
./inter.sh <<-EOF
a
b
c
d
EOF
sleep 10
}
$ inter_child &
$ wait
$ cat actions.log
a
b
c
d
If this doesn't answer your question, please be more specific why you need to create a child process and what's a.out is expecting. Hope this helps!
EDIT:
stdout and stderr are two different redirections.
Write stderr to file 2>: $ ./a.out 2> error.log
Redirect stderr to stdout 2>&1: $ ./a.out > log.log 2>&1

Get PID of last executed command (NO BACKGROUND)

I want to know the PID of the last executed command.
I saw this a lot:
$ command &
$ pid=$!
But I'm searching for the same thing without running the command in the background.
You can use the following construction in scripts:
PID=`sh -c "echo $$; exec your_command -with-arguments"`
echo $PID

Bash script iterate over PID's and kill items

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.

How do I know if a bash script is running with nohup?

I have a script to process records in some files, it usually takes 1-2 hours. When it's running, it prints a progress of number of records processed.
Now, what I want to do is: when it's running with nohup, I don't want it to print the progress; it should print progress only when it run manually.
My question is how do I know if a bash script is running with nohup?
Suppose the command is nohup myscript.sh &. In the script, how do I get the nohup from command line? I tried to use $0, but it gives myscript.sh.
Checking for file redirections is not robust, since nohup can be (and often is) used in scripts where stdin, stdout and/or stderr are already explicitly redirected.
Aside from these redirections, the only thing nohup does is ignore the SIGHUP signal (thanks to Blrfl for the link.)
So, really what we're asking for is a way to detect if SIGHUP is being ignored. In linux, the signal ignore mask is exposed in /proc/$PID/status, in the least-significant bit of the SigIgn hex string.
Provided we know the pid of the bash script we want to check, we can use egrep. Here I see if the current shell is ignoring SIGHUP (i.e. is "nohuppy"):
$ egrep -q "SigIgn:\s.{15}[13579bdf]" /proc/$$/status && echo nohuppy || echo normal
normal
$ nohup bash -c 'egrep -q "SigIgn:\s.{15}[13579bdf]" /proc/$$/status && echo nohuppy || echo normal'; cat nohup.out
nohup: ignoring input and appending output to `nohup.out'
nohuppy
You could check if STDOUT is associated with a terminal:
[ -t 1 ]
You can either check if the parent pid is 1:
if [ $PPID -eq 1 ] ; then
echo "Parent pid=1 (runing via nohup)"
else
echo "Parent pid<>1 (NOT running via nohup)"
fi
or if your script ignores the SIGHUP signal (see https://stackoverflow.com/a/35638712/1011025):
if egrep -q "SigIgn:\s.{15}[13579bdf]" /proc/$$/status ; then
echo "Ignores SIGHUP (runing via nohup)"
else
echo "Doesn't ignore SIGHUP (NOT running via nohup)"
fi
One way, but not really portable would be to do a readlink on /proc/$$/fd/1 and test if it ends with nohup.out.
Assuming you are on the pts0 terminal (not really relevant, just to be able to show the result):
#!/bin/bash
if [[ $(readlink /proc/$$/fd/1) =~ nohup.out$ ]]; then
echo "Running under hup" >> /dev/pts/0
fi
But the traditional approach to such problems is to test if the output is a terminal:
[ -t 1 ]
Thank you guys. Check STDOUT is a good idea. I just find another way to do it. That is to test tty.
test tty -s check its return code. If it's 0 , then it's running on a terminal; if it's 1 then it's running with nohup.

Killing process in Shell Script

I have a very simple problem: When I run a shell script I start a program which
runs in an infinite loop. After a while I wanna stop then this program before I can
it again with different parameters. The question is now how do I find out the pid of
the program when I execute it? Basically, I wanna do something like that:
echo "Executing app1 with param1"
./app1 param1 &
echo "Executing app1"
..do some other stuff
#kill somehow app1
echo "Execution of app1 finished!"
Thanks!
In most shells (including Bourne and C), the PID of the last subprocess you launched in the background will be stored in the special variable $!.
#!/bin/bash
./app1 &
PID=$!
# ...
kill $PID
There is some information here under the Special Variables section.
In bash $! expands to the PID of the last process started in the background. So you can do:
./app1 param1 &
APP1PID=$!
# ...
kill $APP1PID
if you want to find out the PID of a process, you can use ps:
[user#desktop ~]$ ps h -o pid -C app1
the parameter -o pid says that you only want the PID of the process, -C app1 specifies the name of the process you want to query, and the parameter h is used to suppress the header of the result table (without it, you'd see a "PID" header above the PID itself). not that if there's more than one process with the same name, all the PIDs will be shown.
if you want to kill that process, you might want to use:
[user#desktop ~]$ kill `ps h -o pid -C app1`
although killall is cleaner if you just want to do that (and if you don't mind killing all "app1" processes). you can also use head or tail if you want only the first or last PID, respectively.
and a tip for the fish users: %process is replaced with the PID of process. so, in fish, you could use:
user#desktop ~> kill %app1
you obtain the pid of app1 with
ps ux | awk '/app1/ && !/awk/ {print $2}'
and then you should be able to kill it....(however, if you've several instances of app1, you may kill'em all)
pidof app1
pkill -f app1
killall app1
I had a problem where the process I was killing was a python script and I had another script which was also running python. I did not want to kill python because of the other script.
I used awk to deal with this (let myscript be your python script):
kill ps -ef|grep 'python myscript.py'|awk '!/awk/ && !/grep/ {print $2}'
Might not be as efficient but I'd rather trade efficiency for versatility in a task like this.

Resources