5

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
Brad
  • 6,106
  • 4
  • 31
  • 43
  • 1
    You can get the PID of the previous command with `$!`. Then you can use this in the `stop.sh` file. You also have nothing in there to deal with starting multiple times and such. – will Jul 16 '13 at 20:30

5 Answers5

4

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.

kojiro
  • 74,557
  • 19
  • 143
  • 201
Darek
  • 2,861
  • 4
  • 29
  • 52
2

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
kojiro
  • 74,557
  • 19
  • 143
  • 201
2

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
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
1

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.

Jon Kiparsky
  • 7,499
  • 2
  • 23
  • 38
0

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.

will
  • 10,260
  • 6
  • 46
  • 69
  • @Brad It checks if the file exists. See [here](http://tldp.org/LDP/abs/html/fto.html). – will Jul 16 '13 at 20:48