Killing process in Shell Script - linux

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.

Related

Python subprocess.run() to for: kill -HUP `ps -C gunicorn fch -o pid | head -n 1`

I need a Python script subprocess.run() call for the following:
kill -HUP `ps -C gunicorn fch -o pid | head -n 1`
This can't be one long concatenation
subprocess.run(["kill","-HUP","ps","-C","gunicorn","fch","-o","pid","|","head","-n","1"])
How to read the ps -C gunicorn fch -o pid | head -n 1 portion into subprocess.run so it is interpreted by "kill","-HUP" as a quoted string?
The backticks in your original shell code makes a whole separate subprocess for the call to ps. The pipe actually does another process creation, for head!
If you want to do that in pure Python (rather than delegating it all to a shell), you probably want to do at least one additional subprocess call. You probably don't need the one for head, since you can easily read one line of output yourself inside Python.
Try something like:
ps_process = subprocess.Popen(["ps","-C","gunicorn","fch","-o","pid"],
stdout=subprocess.PIPE)
pid_string = next(ps_process.stdout).decode().strip()
subprocess.run(["kill","-HUP", pid_string])
It's also possible that you can send the HUP signal directly from Python, rather than by calling the kill program. And heck, there's probably a module that would let you look up the PIDs of other running programs.

how to fined a process started with nohup after closing terminal?

I have to ssh to a server for running some codes that take a long time to finish. so I need to use nohup command.
I started multiple processes using the nohup command like this:
nohup julia test.jl > Output1.txt &
nohup julia test.jl > Output2.txt &
nohup julia test.jl > Output3.txt &
nohup julia test.jl > Output4.txt &
the problem is that I closed the terminal and when I opened another terminal
I couldn't get the process name and ID using jobs -l.
I tried using ps -p but it answers me for all of the above processes with the same answer julia.
my question is " how can I specify which process is which?" note that only Output file name is different in these processes.
and
"how can I prevent such a problem in the future?"
Thanks for your time and answer.
One way to distinguish between these processes are through there stdout redirections and there is no good way of doing that using ps command.
If you have pgrep installed, you can use that with a simple for loop to know which pid correspond to which output file. Something like the following,
for pid in $(pgrep julia);
do
echo -n "$pid: ";
readlink -f /proc/${pid}/fd/1;
done
/proc/${pid}/fd/1 represents the stdout for the process with pid. It's a symlink, so you need to use readlink to check the source.
Output:
12345: /path/to/output1.txt
12349: /path/to/output2.txt
12350: /path/to/output3.txt
Alternative way would be to use lsof -p $pid, but I find it a bit on the heavy side than what you want to achieve, but the output would be same.
for pid in $(pgrep julia);
do
lsof -p $pid | awk -v var=$pid '/1w/ {print var": "$9}';
done
To find the PIDs of such processes, you can use fuser
$ fuser /path/to/outputfile
or lsof
$ lsof | grep "outputfile"
In order to avoid such a situation in future, use GNU Screen on the server (https://linode.com/docs/networking/ssh/using-gnu-screen-to-manage-persistent-terminal-sessions/).

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.

Access to a process in procfs by name from bash

I want access to the status.log file of some processes, from bash terminal, in a while loop and compare them. So since the PID are not static how can I gain access to their proc/PID files with their command names and not with PID?
Try to grep output from ps -A by name of the command and get PID from there
Assuming you have pgrep (which you should, it's part of procps), call pgrep -x somecmdname to get a list of PIDs matching that string. From there you can access the proc files as usual.
e.g.
for pid in `pgrep -x somecmd`; do
echo $pid #or do something more interesting
done
Try the command pidof:
$ pidof bash
14317 10465 7204 3514 3466
Then you can loop over the pids:
$ for pid in $(pidof bash); do echo "$pid" ; done
14317
10465
7204
3514
3466
You can use this way
Example:
sleep 1000 &
cd /proc/`pidof sleep`
Refer this link man pidof

Shell script to get the process ID on Linux [duplicate]

This question already has answers here:
How to get pid given the process name
(4 answers)
Closed 5 years ago.
I want to write a shell script (.sh file) to get a given process id. What I'm trying to do here is once I get the process ID, I want to kill that process. I'm running on Ubuntu (Linux).
I was able to do it with a command like
ps -aux|grep ruby
kill -9 <pid>
but I'm not sure how to do it through a shell script.
Using grep on the results of ps is a bad idea in a script, since some proportion of the time it will also match the grep process you've just invoked. The command pgrep avoids this problem, so if you need to know the process ID, that's a better option. (Note that, of course, there may be many processes matched.)
However, in your example, you could just use the similar command pkill to kill all matching processes:
pkill ruby
Incidentally, you should be aware that using -9 is overkill (ho ho) in almost every case - there's some useful advice about that in the text of the "Useless Use of kill -9 form letter ":
No no no. Don't use kill -9.
It doesn't give the process a chance to cleanly:
shut down socket connections
clean up temp files
inform its children that it is going away
reset its terminal characteristics
and so on and so on and so on.
Generally, send 15, and wait a second or two, and if that doesn't
work, send 2, and if that doesn't work, send 1. If that doesn't,
REMOVE THE BINARY because the program is badly behaved!
Don't use kill -9. Don't bring out the combine harvester just to tidy
up the flower pot.
If you are going to use ps and grep then you should do it this way:
ps aux|grep r[u]by
Those square brackets will cause grep to skip the line for the grep command itself. So to use this in a script do:
output=`ps aux|grep r\[u\]by`
set -- $output
pid=$2
kill $pid
sleep 2
kill -9 $pid >/dev/null 2>&1
The backticks allow you to capture the output of a comand in a shell variable. The set -- parses the ps output into words, and $2 is the second word on the line which happens to be the pid. Then you send a TERM signal, wait a couple of seconds for ruby to to shut itself down, then kill it mercilessly if it still exists, but throw away any output because most of the time kill -9 will complain that the process is already dead.
I know that I have used this without the backslashes before the square brackets but just now I checked it on Ubuntu 12 and it seems to require them. This probably has something to do with bash's many options and the default config on different Linux distros. Hopefully the [ and ] will work anywhere but I no longer have access to the servers where I know that it worked without backslash so I cannot be sure.
One comment suggests grep-v and that is what I used to do, but then when I learned of the [] variant, I decided it was better to spawn one fewer process in the pipeline.
As a start there is no need to do a ps -aux | grep... The command pidof is far better to use. And almost never ever do kill -9 see here
to get the output from a command in bash, use something like
pid=$(pidof ruby)
or use pkill directly.
option -v is very important. It can exclude a grep expression itself
e.g.
ps -w | grep sshd | grep -v grep | awk '{print $1}' to get sshd id
This works in Cygwin but it should be effective in Linux as well.
ps -W | awk '/ruby/,NF=1' | xargs kill -f
or
ps -W | awk '$0~z,NF=1' z=ruby | xargs kill -f
Bash Pitfalls
You can use the command killall:
$ killall ruby
Its pretty simple.
Simply Run Any Program like this :- x= gedit & echo $! this will give you PID of this process.
then do this kill -9 $x
To kill the process in shell
getprocess=`ps -ef|grep servername`
#echo $getprocess
set $getprocess
pid=$2
#echo $pid
kill -9 $pid
If you already know the process then this will be useful:
PID=`ps -eaf | grep <process> | grep -v grep | awk '{print $2}'`
if [[ "" != "$PID" ]]; then
echo "killing $PID"
kill -9 $PID
fi

Resources