I am trying to run a sript in the background:
nohup script.py > out 2> err < /dev/null &
The script (Python 3.4
) does at some point:
answer = input('? ')
(it has a menu running in one of the threads)
And the nohup call is crashing with:
EOFError: EOF when reading a line
Because of the /dev/null
redirection of stdin
I imagine. If I run it without stdin
redirection:
nohup script.py > out 2> err &
It crashes with:
OSError: [Errno 9] Bad file descriptor
If I run it with:
script.py > out 2> err
It works, but blocks my terminal (it is in the foreground)
If I run it with:
script.py > out 2> err &
It runs in the background alright, but it gets stopped as soon as the input
call is reached.
What I would like is:
- be able to redirect
stdout
andstderr
to the filesystem - be able to put the script in the background
- be able to move if to the foreground and interact with the menu normally (so
stdin
must be enabled somehow).stdout
andstderr
would still be redirected to the filesystem, butstdin
would behave normally. - the script must run fine in the background and in the foreground (of course, the menu is not working in the background, because
stdin
is "frozen")
Basically, what I would like is that when it is in the background, stdin
is kind of "frozen", and whenever it comes to the foreground it works again normally.
Is this possible? The solution does not need to involve nohup
What you want (and how
input
works and fails onEOF
under python) with an interactive menu means that you cannot safely pass a file asstdin
when invoking your program. This means your only option is to invoke this like so:As a demonstration, this is my script:
Essentially, every second it will write to
stdout
, every two seconds it will write tostderr
, and lastly, every ten seconds it will wait for input. If I were to run this and wait a bit over a seconds (to allow disk flush), and chain this together, like so:Wait at least 10 seconds and try
cat out err
again:Note that the prompt generated by
input
is also written to stdout, and the program effectively continued running up to where it is expectingstdin
to give it data. You simply have to bring the process back into foreground by%
, and start feeding it the required data, then suspend with^Z
(CtrlZ) and keep it running again in the background with%&
. Example:Now
cat out
again, after waiting another ten seconds:This is essentially a basic crash course in how standard processes typically functions in both foreground and background, and things just simply work as intended if the code handles the standard IO correctly.
Lastly, you can't really have it both ways. If the application expects stdin and none is provided, then the clear option is failure. If one is provided however but application got sent to background and kept running, it will be
Stopped
as it expects further input. If this stopped behaviour is unwanted, the application is at fault, there is nothing can be done but to change the application to not result in an error whenEOF
is encountered when executed with/dev/null
as itsstdin
. If you want to keepstdin
as is, with the application being able to somehow keep running when it is in the background you cannot use theinput
function as it will block whenstdin
is empty (resulting in process being stopped).Now that you have clarified via the comment below that your "interactive prompt" is running in a thread, and since usage of
input
directly reads fromstdin
and you seem unwilling to modify your program (you asking for general case) but expects a utility to do this for you, the simple solution is to execute this within atmux
orscreen
session as they fully implement a pseudo tty that is independent from whichever console that started (so you can disconnect and send the session to the background, or start other virtual sessions, see manual pages) which will provide stdio that the program expects.Finally, if you actually want your application to support this natively, you cannot simply use
input
as is, but you should check whetherinput
can safely be called (i.e. perhaps making use ofselect
), or by checking whether the process is currently in the foreground or background (An example you could start working from is How to detect if python script is being run as a background process, although you might want to check usingsys.stdin
, maybe.) to determine ifinput
can be safely called (however if user suspends the task as input comes it would still hang asinput
waits), or use unix sockets for communication.