14

Is there a way to tell whether my python script is running as a background process or not? I'm trying to differentiate between these two:

sudo ./myscript.py
sudo ./myscript.py &

Using sys.argv doesn't work - the ampersand doesn't count as an argument apparently. And what would be the effect of the following instead:

sudo python myscript.py
sudo python myscript.py &

I've had a look around, but everything seems to be about starting a background process from within a Python script, not whether the Python script itself is a background process. Thanks!

EDIT: The aim is to output a message (or not), i.e. "Press Ctrl+C to stop this script" if started normally, but don't display the message if started as a background process.

EDIT 2 I neglected to mention that this python script will be started by a script in /etc/init.d rather than from a terminal prompt. So the answer marked as correct does indeed answer the question as I phrased it and with the information given, but I thought I should point out that it doesn't work in the init.d scenario, to avoid any potential confusion in the future.

HaydnW
  • 311
  • 1
  • 4
  • 10
  • I don't think so. What do you want to achieve? – Aaron Digulla Jul 21 '14 at 09:11
  • Thanks Aaron. I've added to the original request to clarify. – HaydnW Jul 21 '14 at 09:25
  • When the process is detached, reading from `stdin` will block it. Writing to `stdout` works, though. I don't know a way to check whether reading `stdin` would block, though. – Aaron Digulla Jul 21 '14 at 09:30
  • 3
    Answer for C code: http://stackoverflow.com/questions/14894261/programmatically-check-if-a-process-is-being-run-in-the-background – Aaron Digulla Jul 21 '14 at 09:32
  • possible duplicate of [Checking for interactive shell in a Python script](http://stackoverflow.com/questions/6108330/checking-for-interactive-shell-in-a-python-script) – Lie Ryan Jul 21 '14 at 10:00

3 Answers3

8

Based on the answer for C @AaronDigulla pointed to in a comment:

import os
import sys


def main():
    if os.getpgrp() == os.tcgetpgrp(sys.stdout.fileno()):
        print 'Running in foreground.'
    else:
        print 'Running in background.'


if __name__ == '__main__':
    main()
Community
  • 1
  • 1
BlackJack
  • 4,476
  • 1
  • 20
  • 25
  • 3
    Example given above worked perfectly, to a degree. :) I'm actually running the script using a script in /etc/init.d on Linux, rather than through a terminal. The example given works brilliantly when I start the Python script at a terminal prompt, but fails with `OSError: [Errno 25] Inappropriate ioctl for device` when run via the init.d script. I'll keep looking! :) – HaydnW Jul 21 '14 at 15:27
  • 2
    Wrap the call to `os.tcgetpgrp` in a try/except block and if throws an `OSError` then you know `sys.stdout` isn't a terminal. In that case it's probably safe to assume that no one is going to be able read the message. CTRL-C probably also won't work. – Ross Ridge Jul 21 '14 at 21:13
  • Technically, calling "nohup python code.py > output_file.txt" is not running the code in background, but this answer tells me so. – Pablo Apr 30 '19 at 08:03
2

I saw the other solutions on other and decided to write a pure python solution. It reads from /proc/<pid>/stat rather than calling a subprocess.

from os import getpid

with open("/proc/{}/stat".format(getpid())) as f:
    data = f.read()

foreground_pid_of_group = data.rsplit(" ", 45)[1]
is_in_foreground = str(getpid()) == foreground_pid_of_group

The meanings of the columns of the stat file can be found here

Dunes
  • 37,291
  • 7
  • 81
  • 97
1

Based on bash solution from this answer:

import os
import subprocess
pid = os.getpid()
if "+" in subprocess.check_output(["ps", "-o", "stat=", "-p", str(pid)]):
  print "Running in foreground"
else:
  print "Running in background"
Community
  • 1
  • 1
RomanHotsiy
  • 4,978
  • 1
  • 25
  • 36