shell start / stop for python script - python

I have a simple python script i need to start and stop and i need to use a start.sh and stop.sh script to do it.
I have start.sh:
#!/bin/sh
script='/path/to/my/script.py'
echo 'starting $script with nohup'
nohup /usr/bin/python $script &
and stop.sh
#!/bin/sh
PID=$(ps aux | grep "/path/to/my/script.py" | awk '{print $2}')
echo "killing $PID"
kill -15 $PID
I'm mainly concerned with the stop.sh script. I think that's an appropriate way to find the pid but i wouldn't bet much on it. start.sh successfully starts it. when i run stop.sh, i can no longer find the process by "ps aux | grep 'myscript.py'" but the console outputs:
killing 25052
25058
./stop.sh: 5: kill: No such process
so it seems like it works AND gives an error of sorts with "No such process".
Is this actually an error? Am I approaching this in a sane way? Are there other things I should be paying attention to?
EDIT - I actually ended up with something like this:
start.sh
#!/bin/bash
ENVT=$1
COMPONENTS=$2
TARGETS=("/home/user/project/modules/script1.py" "/home/user/project/modules/script2.py")
for target in "${TARGETS[#]}"
do
PID=$(ps aux | grep -v grep | grep $target | awk '{print $2}')
echo $PID
if [[ -z "$PID" ]]
then
echo "starting $target with nohup for env't: $ENVT"
nohup python $target $ENVT $COMPONENTS &
fi
done
stop.sh
#!/bin/bash
ENVT=$1
TARGETS=("/home/user/project/modules/script1.py" "/home/user/project/modules/script2.py")
for target in "${TARGETS[#]}"
do
pkill -f $target
echo "killing process $target"
done

It is because ps aux |grep SOMETHING also finds the grep SOMETHING process, because SOMETHING matches. After the execution the grep is finished, so it cannot find it.
Add a line: ps aux | grep -v grep | grep YOURSCRIPT
Where -v means exclude. More in man grep.

The "correct" approach would probably be to have your script write its pid to a file in /var/run, and clear it out when you kill the script. If changing the script is not an option, have a look at start-stop-daemon.
If you want to continue with the grep-like approach, have a look at proctools. They're built in on most GNU/Linux machines and readily available on BSD including OS X:
pkill -f /path/to/my/script.py

init-type scripts are useful for this. This is very similar to one I use. You store the pid in a file, and when you want to check if it's running, look into the /proc filesystem.
#!/bin/bash
script_home=/path/to/my
script_name="$script_home/script.py"
pid_file="$script_home/script.pid"
# returns a boolean and optionally the pid
running() {
local status=false
if [[ -f $pid_file ]]; then
# check to see it corresponds to the running script
local pid=$(< "$pid_file")
local cmdline=/proc/$pid/cmdline
# you may need to adjust the regexp in the grep command
if [[ -f $cmdline ]] && grep -q "$script_name" $cmdline; then
status="true $pid"
fi
fi
echo $status
}
start() {
echo "starting $script_name"
nohup "$script_name" &
echo $! > "$pid_file"
}
stop() {
# `kill -0 pid` returns successfully if the pid is running, but does not
# actually kill it.
kill -0 $1 && kill $1
rm "$pid_file"
echo "stopped"
}
read running pid < <(running)
case $1 in
start)
if $running; then
echo "$script_name is already running with PID $pid"
else
start
fi
;;
stop)
stop $pid
;;
restart)
stop $pid
start
;;
status)
if $running; then
echo "$script_name is running with PID $pid"
else
echo "$script_name is not running"
fi
;;
*) echo "usage: $0 <start|stop|restart|status>"
exit
;;
esac

ps aux | grep "/path/to/my/script.py"
will return both the pid for the instance of script.py and also for this instance of grep. That'll probably be why you're getting a no such process: by the time you get around to killing the grep, it's already dead.

I don't have a unix box on at the moment, so i can't test this, but it should be fairly simple to get the idea.
start.sh:
if [ -e ./temp ]
then
pid=`cat temp`
echo "Process already exists; $pid"
else
script='/path/to/my/script.py'
echo 'starting $script with nohup'
nohup /usr/bin/python $script &
echo $! > temp
fi
stop.sh:
if [ -e ./temp ]
then
pid=`cat temp`
echo "killing $pid"
kill -15 $PID
rm temp
else
echo "Process not started"
fi
Try this out.

Related

daemonizing a python script: What is better? start-stop-daemon or python-daemon

I like to start a python program as a daemon. I checked a bit the internet and came up with two solutions.
The first one is to use start-stop-daemon on something like this
#!/bin/sh
start() {
start-stop-daemon -S -q -m -b -p /var/run/sample.pid --exec /usr/bin/python /bin/sample.py && echo "OK" || echo "Failed"
}
stop() {
start-stop-daemon -K -q -p /var/run/sample.pid
}
case "${1}" in
start)
start
echo "sample service started"
;;
stop)
stop
echo "sample service stopped"
;;
restart)
stop
start
echo "sample service restarted"
;;
*)
echo "usage: $0 {start|stop|restart}"
;;
esac
The second one is to use python-daemon
so I guess we have an extra python file - lets name it "sampleDaemon.py"
import daemon
import sample
with daemon.DaemonContext():
sample()
And a bash script (I am not sure about that - I guess this way):
#!/bin/sh
/usr/bin/python /bin/sampleDeamon.py
What is the best way to do it? What are the limitations? The python-deamon documentation is not that big(or I didn't found it).

How to pipe a Python's cmd class' input/output to another Python process?

Currently, I'm running an experiment with Mininet-Wifi. It's CLI is Python's Cmd module and this is how I am able to get accurate information about the simulated network environment. The simulator is running as its own process as sudo python on Ubuntu 14.04 or greater.
The remote controller for this network is POX. This time, only a script is running; everything is automated with preset commands - no more human interaction. What I would like to do is: the POX process needs to inject commands into the Mininet's process and retrieve the results of the execution of that command. This is because POX's logic must constantly query the state of the network via Mininet to be able to make decisions. When a decision has been made, POX must again inject a command into the Mininet process to alter the state of the network.
ADDENDUM: Currently, I am only able to access the hosts that are spawned by Mininet when I run the sudo python a_mininet_script, thanks to the utility function called m. After spawning the hosts, Mininet enters its CLI function, which is what I want to communicate with but can't. This is Mininet's m function.
#!/bin/bash
# Attach to a Mininet host and run a command
if [ -z $1 ]; then
echo "usage: $0 host cmd [args...]"
exit 1
else
host=$1
fi
pid=`ps ax | grep "mininet:$host$" | grep bash | grep -v mnexec | awk '{print $1};'`
if echo $pid | grep -q ' '; then
echo "Error: found multiple mininet:$host processes"
exit 2
fi
if [ "$pid" == "" ]; then
echo "Could not find Mininet host $host"
exit 3
fi
if [ -z $2 ]; then
cmd='bash'
else
shift
cmd=$*
fi
cgroup=/sys/fs/cgroup/cpu/$host
if [ -d "$cgroup" ]; then
cg="-g $host"
fi
# Check whether host should be running in a chroot dir
rootdir="/var/run/mn/$host/root"
if [ -d $rootdir -a -x $rootdir/bin/bash ]; then
cmd="'cd `pwd`; exec $cmd'"
cmd="chroot $rootdir /bin/bash -c $cmd"
fi
cmd="exec sudo mnexec $cg -a $pid $cmd"
eval $cmd
For example, to access the terminal of h1 from any terminal, not from the POX script, I'd call it thus:
sh m h1 ifconfig
But to call it from subprocess, it would be:
p = subprocess.Popen('echo my passwd | sudo -kS sh m h1 ifconfig', shell = True)
To repeat my question, I want to communicate with the CLI of the Mininet process from the POX controller, and not just the spawned hosts.
I guess you want to realize the function something like netstat -oan | findstr 80 (this is on windows to find the port 80), this is the pipeline command to pass the output of netstat -oan to the command findstr.
Then the python code is something like:
import subprocess
p1 = subprocess.Popen('netstat -oan', stdout=subprocess.PIPE, shell=True)
p2 = subprocess.Popen('findstr 80', stdin=p1.stdout, stdout=subprocess.PIPE, shell=True)
pipeline_output = p2.communicate()[0]
print pipeline_output
Then, the p1 process output will be passed to p2 process, FYI.

Run python command from bash ubuntu

I have installed odoo 8.0 (formerly openerp) source in my ubuntu 14.04
When i try this command (to run odoo server) from terminal
python odoo.py
it was run normally.
But, how can i know the return value of python command?
i want to see if the command running normally, or
it is raise an exception?
So i can make *.sh file to run that command.
I have tried this code
if [ -f odoo.py ]; then
python odoo.py
rc=$?;
if [ $rc !=0 ]; then
echo "Error when starting odoo-server,"
echo "Odoo-server not started."
else
sleep 1
echo "Odoo-server started."
fi
else
echo "Cannot found odoo.py"
echo "Odoo-server not started."
fi
but, when the command fail
it is always give me this output
Odoo-server started
Any one can help me?
Your spacing is wrong:
if [ $rc !=0 ]; then
Should be:
if [ $rc != 0 ]; then
But that is a text test, an arithmetic test would be:
if [ $rc -ne 0 ]; then
or preferably:
if (( rc != 0 )); then
However, a better way would be:
if python odoo.py
then
sleep 1
echo "Odoo-server started."
else
echo "Error when starting odoo-server," >&2
echo "Odoo-server not started." >&2
fi

how to add getopt options in a bash script

I have written a bash script that consists of multiple Unix commands and Python scripts. The goal is to make a pipeline for detecting long non coding RNA from a certain input. Ultimately I would like to turn this into an 'app' and host it on some bioinformatics website. One problem I am facing is using getopt tools in bash. I couldn't find a good tutorial that I understand clearly. In addition any other comments related to the code is appreciated.
#!/bin/bash
if [ "$1" == "-h" ]
then
echo "Usage: sh $0 cuffcompare_output reference_genome blast_file"
exit
else
wget https://github.com/TransDecoder/TransDecoder/archive/2.0.1.tar.gz && tar xvf 2.0.1 && rm -r 2.0.1
makeblastdb -in $3 -dbtype nucl -out $3.blast.out
grep '"u"' $1 | \
gffread -w transcripts_u.fa -g $2 - && \
python2.7 get_gene_length_filter.py transcripts_u.fa transcripts_u_filter.fa && \
TransDecoder-2.0.1/TransDecoder.LongOrfs -t transcripts_u_filter.fa
sed 's/ .*//' transcripts_u_filter.fa | grep ">" | sed 's/>//' > transcripts_u_filter.fa.genes
cd transcripts_u_filter.fa.transdecoder_dir
sed 's/|.*//' longest_orfs.cds | grep ">" | sed 's/>//' | uniq > longest_orfs.cds.genes
grep -v -f longest_orfs.cds.genes ../transcripts_u_filter.fa.genes > longest_orfs.cds.genes.not.genes
sed 's/^/>/' longest_orfs.cds.genes.not.genes > temp && mv temp longest_orfs.cds.genes.not.genes
python ../extract_sequences.py longest_orfs.cds.genes.not.genes ../transcripts_u_filter.fa longest_orfs.cds.genes.not.genes.fa
blastn -query longest_orfs.cds.genes.not.genes.fa -db ../$3.blast.out -out longest_orfs.cds.genes.not.genes.fa.blast.out -outfmt 6
python ../filter_sequences.py longest_orfs.cds.genes.not.genes.fa.blast.out longest_orfs.cds.genes.not.genes.fa.blast.out.filtered
grep -v -f longest_orfs.cds.genes.not.genes.fa.blast.out.filtered longest_orfs.cds.genes.not.genes.fa > lincRNA_final.fa
fi
Here is how I run it:
sh test.sh cuffcompare_out_annot_no_annot.combined.gtf /mydata/db/Brapa_sequence_v1.2.fa TE_RNA_transcripts.fa
If you wanted the call to be :
test -c cuffcompare_output -r reference_genome -b blast_file
You would have something like :
#!/bin/bash
while getopts ":b:c:hr:" opt; do
case $opt in
b)
blastfile=$OPTARG
;;
c)
comparefilefile=$OPTARG
;;
h)
echo "USAGE : test -c cuffcompare_output -r reference_genome -b blast_file"
;;
r)
referencegenome=$OPTARG
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
In the string ":b:c:hr:",
- the first ":" tells getopts that we'll handle any errors,
- subsequent letters are the allowable flags. If the letter is followed by a ':', then getopts will expect that flag to take an argument, and supply that argument as $OPTARG

BASH - crontab is always running except the python script

When i run this script from shell /var/tmp/server_always_alive.sh manually has no problem works. But when i let it run with crontab it never running even all the logics are correct.
How can i make the python server.py run via this crontab?
sun#sun-Inspiron-One-2320:~$ uname -a
Linux sun-Inspiron-One-2320 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:31:23 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
/var/tmp/server_always_alive.sh:
#!/bin/bash
echo "test 1"
echo "test 2"
# 58888 TCP port is server port of server.py, if its not running server.py has to execute auto
main=$(export DISPLAY=:0.0 && lsof -i tcp:58888 | grep LISTEN | awk '{print $2}')
if [ -z "$main" ]; then
export DISPLAY=:0.0 && python /var/tmp/python/server.py &
sleep 2
break
fi
echo "test 3"
echo "all runs except python server.py"
crontab :
* * * * * /var/tmp/server_always_alive.sh &
DISPLAY=:0.0 indicates your python 'server' is connecting to an X server. Why?
Cron won't have the necessary X "cookie". , and almost certainly won't be running as the same user as the X server.
edit: I'll take you at your word that you're running as the correct user.
edit: If you really need to run a graphical program from cron, try
xhost +si:localuser:`whoami`
For reference to alternative workout.
Step 1: Put python script on this following script= save it in /var/tmp/main.sh
A) NON GUI BASED
#!/bin/sh
script='/my/python/script/is/here/ok.py'
/usr/bin/python $script &
B) GUI (GTK/TK etc)
#!/bin/sh
script='/my/python/script/is/here/ok.py'
export DISPLAY=:0.0 && /usr/bin/python $script &
Step 2: now make a file in /etc/init.d/scriptname_what_ever_feed_i_name with following (copy paste)
#! /bin/sh
PATH=/bin:/usr/bin:/sbin:/usr/sbin
DAEMON=/home/CHANGE _ ____ HERE ______ to the Step 1 file name
PIDFILE=/var/run/scriptname.pid
test -x $DAEMON || exit 0
. /lib/lsb/init-functions
case "$1" in
start)
log_daemon_msg "Starting feedparser"
start_daemon -p $PIDFILE $DAEMON
log_end_msg $?
;;
stop)
log_daemon_msg "Stopping feedparser"
killproc -p $PIDFILE $DAEMON
PID=`ps x |grep feed | head -1 | awk '{print $1}'`
kill -9 $PID
log_end_msg $?
;;
force-reload|restart)
$0 stop
$0 start
;;
status)
status_of_proc -p $PIDFILE $DAEMON atd && exit 0 || exit $?
;;
*)
echo "Usage: /etc/init.d/atd {start|stop|restart|force-reload|status}"
exit 1
;;
esac
exit 0
Step 3: make it executeable chmod +x /etc/init.d/scriptname_what_ever_feed_i_name and chmod -R 777 /etc/init.d/scriptname_what_ever_feed_i_name so that as any user you can execute it without sudo.
Step 4: for example:
/etc/init.d/scriptname_what_ever_feed_i_name restart
or
* * * * * /etc/init.d/scriptname_what_ever_feed_i_name restart
WORKING - and much better/safer.
ps aux | grep python
root 5026 0.5 0.3 170464 19336 pts/0 S 07:40 0:00 /usr/bin/python /var/tmp/python/server.py
Now you can start and stop your python script using the command /etc/init.d/scriptname start or stop manually or cron etc

Categories