1

I have a Python script that runs in an infinite loop (it's a server).

I want to write an AppleScript that will start this script if it isn't started yet, and otherwise force-quit and restart it. This will make it easy for me to make changes to the server code while programming.

Currently I only know how to start it: do shell script "python server.py"

2
  • This is too broad. Please include the script, what server, and what you have done so far. Commented Nov 29, 2016 at 19:54
  • The content of the python script really doesn't matter. It's an infinite loop, that's all applescript needs to know. Also, I did write what I have done so far: 'do shell script "python server.py"' is an applescript that starts the server. I need to know how to close it again. Commented Nov 29, 2016 at 19:58

2 Answers 2

1

Note that AppleScript's do shell script starts the shell (/bin/sh) in the root directory (/) by default, so you should specify an explicit path to server.py

In the following examples I'll assume directory path ~/srv.

Here's the shell command:

pid=$(pgrep -fx 'python .*/server\.py'); [ "$pid" ] && kill -9 $pid; python ~/srv/server.py

As an AppleScript statement, wrapped in do shell script - note the \-escaped inner " and \ chars.:

do shell script "pid=$(pgrep -fx 'python .*/server\\.py'); [ \"$pid\" ] && kill -9 $pid; python ~/srv/server.py"
  • pgrep -fx '^python .*/server\.py$' uses pgrep to find your running command by regex against the full command line (-f), requiring a full match (-x), and returns the PID (process ID), if any.

    • Note that I've used a more abstract regex to underscore the fact that pgrep (always) treats its search term as a regular expression.
      To specify the full launch command line as the regex, use python ~/srv/server\.py - note the \-escaping of . for full robustness.
  • [ "$pid" ] && kill -9 $pid kills the process, if a PID was found ([ "$pid" ] is short for [ -n "$pid" ] and evaluates to true only if $pid is nonempty); -9 sends signal SIGKILL, which forcefully terminates the process.

  • python ~/srv/server.py then (re)starts your server.

Sign up to request clarification or add additional context in comments.

Comments

1

On the shell, if you do ps aux | grep python\ server.py | head -n1, you'll get the ID of the process running server.py. You can then use kill -9 to kill that process and restart it:

kill -9 `ps aux | grep python\ server.py | head -n1 | python -c 'import sys; print(sys.stdin.read().split()[1])'`

That'll kill it. Al you have to do now is to restart it:

python server.py

You can combine the two with &&:

kill -9 `ps aux | grep python\ server.py | head -n1 | python -c 'import sys; print(sys.stdin.read().split()[1])'` && python server.py

Of course, you already know how to put that in a do shell script!

12 Comments

Looks like it almost works, but I get an error: "sh: line 0: kill: socks python\\ /Volumes/path/server.py | head -n1 | python -c 'import sys; print(sys.stdin.read().split()[1])': arguments must be process or job IDs"
My script was: do shell script "kill -9 \"socks python\\ /Volumes/path/server.py | head -n1 | python -c 'import sys; print(sys.stdin.read().split()[1])'\" && python /Volumes/path/server.py"
@FlorianDietz: Sorry, I used an alias that doesn't exist on your computer. Check out the edit. Also, you'll need to change your script to grep server.py instead of the full path of server.py
I am getting the same error for: do shell script "kill -9 \"ps aux python\\ grep server.py | head -n1 | python -c 'import sys; print(sys.stdin.read().split()[1])'\" && python /Volumes/path/server.py"
@FlorianDietz: note that it's `ps aux, not "ps aux. Note the backtick -it's above the TAB key
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.