1

I have a simple question. I have tried to search for a solution but there are no answers which would explain what I need.

The question is: How do I start a nohup command from Python? Basically the idea is, that I have a Python script which prepares my environment and I need it to launch multiple scripts with nohup commands. How do I start a nohup command like nohup python3 my_script.py & from within a running Python script to have that nohup command running even after I log out?

Thank you

7
  • did you check this post? stackoverflow.com/questions/37118991/… Commented Oct 21, 2021 at 15:13
  • In general, nohup is useless even in bash -- it does nothing you can't do just with some redirections and potentially the shell disown builtin (which has, and needs, no Python equivalent). There's no reason to use it in Python; none whatsoever. Commented Oct 21, 2021 at 15:21
  • subprocess.Popen(['python3', 'my_script.py'], stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, start_new_session=True) -- replace the subprocess.DEVNULLs for stdout and stderr with pointers to a file if you want (nohup's own default is nohup.out, but you can call it anything you want). Commented Oct 21, 2021 at 15:23
  • (that said, if your goal is to start a service, the right way to do that is to go through your operating system's init system -- systemd has a concept of transient user services, if that's what you want; whereas if you want to emulate a system service, the advantages of setting it up through systemd are even stronger). Commented Oct 21, 2021 at 15:25
  • Thank you everyone for your replies. @CharlesDuffy what do you suggest then for executing a Python script, from Python script, to run in the background endlessly? Commented Oct 21, 2021 at 15:26

1 Answer 1

3

You do not need nohup -- not even in shell, and even less so in Python. It does the following things:

  • Configures the HUP signal to be ignored (rarely relevant: if a process has no handles on a TTY it isn't going to be notified when that TTY exits regardless; the shell only propagates signals to children in interactive mode, not when running scripts).
  • If stdout is a terminal, redirects it to nohup.out
  • If stderr is a terminal, redirects it to wherever stdout was already redirected.
  • Redirects stdin to /dev/null

That's it. There's no reason to use nohup to do any of those things; they're all trivial to do without it:

  • </dev/null redirects stdin from /dev/null in shell; stdin=subprocess.DEVNULL does so in Python.
  • >nohup.out redirects stdout to nohup.out in shell; stdout=open('nohup.out', 'w') does so in Python.
  • 2>&1 makes stderr go to the same place as stdout in shell; stderr=subprocess.STDOUT does so in Python.

Because your process isn't attached to the terminal by virtue of the above redirections, it won't implicitly get a HUP when that terminal closes. If you're worried about a signal being sent to the parent's entire process group, however, you can avoid that by splitting off the child into a separate one:

  • The subprocess.Popen argument start_new_session=True splits the child process into a separate group from the parent in Python, so a parent sent to the process group of the parent as a whole will not be received by the child.
  • Adding a preexec_fn with signal.signal(signal.SIGHUP, signal.SIG_IGN) is even more explicit that the child should by default ignore a SIGHUP even if one is received.

Putting this all together might look like (if you really do want logs to go to a file named nohup.out -- I would suggest picking a better name):

import subprocess, signal
subprocess.Popen(['python3', 'my_script.py'],
                 stdin=subprocess.DEVNULL,
                 stdout=open('nohup.out', 'w'),
                 stderr=subprocess.STDOUT,
                 start_new_session=True,
                 preexec_fn=(lambda: signal.signal(signal.SIGHUP, signal.SIG_IGN)))
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you for your extensive explanation. I'm still a bit confused on how to proceed though. Would you, please, add a short example Python code on how to create the equivalent of nohup in Python? Thank you very much
@neisor Refer the documentation for subprocess.Popen . The arguments to provide are listed out in this answer
Thank you very much! I appreciate your extensive explanation and help.
@DanNagle, ...why add an explanation of a bug in the code, vs just proposing an edit that fixes that bug? (There's no reasonable interpretation that that was by intent, because the prose explanation above the code describes signal.SIGHUP as the correct thing).
@CharlesDuffy My edit was to move the added remark out of the code fragment.
|

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.