Redirect stdout to a file in Python?





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







265















How do I redirect stdout to an arbitrary file in Python?



When a long-running Python script (e.g, web application) is started from within the ssh session and backgounded, and the ssh session is closed, the application will raise IOError and fail the moment it tries to write to stdout. I needed to find a way to make the application and modules output to a file rather than stdout to prevent failure due to IOError. Currently, I employ nohup to redirect output to a file, and that gets the job done, but I was wondering if there was a way to do it without using nohup, out of curiosity.



I have already tried sys.stdout = open('somefile', 'w'), but this does not seem to prevent some external modules from still outputting to terminal (or maybe the sys.stdout = ... line did not fire at all). I know it should work from simpler scripts I've tested on, but I also didn't have time yet to test on a web application yet.










share|improve this question
























  • 7





    That's not really a python thing, it's a shell function. Just run your script like script.p > file

    – Falmarri
    Jan 13 '11 at 0:52











  • I currently solve the problem using nohup, but I thought there might be something more clever...

    – hayavuk
    Jan 13 '11 at 0:59






  • 1





    @foxbunny: nohup? Why simply someprocess | python script.py? Why involve nohup?

    – S.Lott
    Jan 13 '11 at 1:39






  • 3





    Rewrite the print statements to apply the logging module from the stdlib. Then you can redirect output everywhere, have control over how much output you want etc. In most cases production code should not print but log.

    – erikbwork
    Jan 3 '14 at 7:44






  • 2





    Perhaps a better solution for this problem is the screen command, which will save your bash session and allow you to access it from different runs.

    – Ryan Amos
    May 5 '14 at 23:08


















265















How do I redirect stdout to an arbitrary file in Python?



When a long-running Python script (e.g, web application) is started from within the ssh session and backgounded, and the ssh session is closed, the application will raise IOError and fail the moment it tries to write to stdout. I needed to find a way to make the application and modules output to a file rather than stdout to prevent failure due to IOError. Currently, I employ nohup to redirect output to a file, and that gets the job done, but I was wondering if there was a way to do it without using nohup, out of curiosity.



I have already tried sys.stdout = open('somefile', 'w'), but this does not seem to prevent some external modules from still outputting to terminal (or maybe the sys.stdout = ... line did not fire at all). I know it should work from simpler scripts I've tested on, but I also didn't have time yet to test on a web application yet.










share|improve this question
























  • 7





    That's not really a python thing, it's a shell function. Just run your script like script.p > file

    – Falmarri
    Jan 13 '11 at 0:52











  • I currently solve the problem using nohup, but I thought there might be something more clever...

    – hayavuk
    Jan 13 '11 at 0:59






  • 1





    @foxbunny: nohup? Why simply someprocess | python script.py? Why involve nohup?

    – S.Lott
    Jan 13 '11 at 1:39






  • 3





    Rewrite the print statements to apply the logging module from the stdlib. Then you can redirect output everywhere, have control over how much output you want etc. In most cases production code should not print but log.

    – erikbwork
    Jan 3 '14 at 7:44






  • 2





    Perhaps a better solution for this problem is the screen command, which will save your bash session and allow you to access it from different runs.

    – Ryan Amos
    May 5 '14 at 23:08














265












265








265


107






How do I redirect stdout to an arbitrary file in Python?



When a long-running Python script (e.g, web application) is started from within the ssh session and backgounded, and the ssh session is closed, the application will raise IOError and fail the moment it tries to write to stdout. I needed to find a way to make the application and modules output to a file rather than stdout to prevent failure due to IOError. Currently, I employ nohup to redirect output to a file, and that gets the job done, but I was wondering if there was a way to do it without using nohup, out of curiosity.



I have already tried sys.stdout = open('somefile', 'w'), but this does not seem to prevent some external modules from still outputting to terminal (or maybe the sys.stdout = ... line did not fire at all). I know it should work from simpler scripts I've tested on, but I also didn't have time yet to test on a web application yet.










share|improve this question
















How do I redirect stdout to an arbitrary file in Python?



When a long-running Python script (e.g, web application) is started from within the ssh session and backgounded, and the ssh session is closed, the application will raise IOError and fail the moment it tries to write to stdout. I needed to find a way to make the application and modules output to a file rather than stdout to prevent failure due to IOError. Currently, I employ nohup to redirect output to a file, and that gets the job done, but I was wondering if there was a way to do it without using nohup, out of curiosity.



I have already tried sys.stdout = open('somefile', 'w'), but this does not seem to prevent some external modules from still outputting to terminal (or maybe the sys.stdout = ... line did not fire at all). I know it should work from simpler scripts I've tested on, but I also didn't have time yet to test on a web application yet.







python stdout






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Oct 5 '15 at 15:17









Eric Leschinski

90.8k40331282




90.8k40331282










asked Jan 13 '11 at 0:51









hayavukhayavuk

4,92853243




4,92853243













  • 7





    That's not really a python thing, it's a shell function. Just run your script like script.p > file

    – Falmarri
    Jan 13 '11 at 0:52











  • I currently solve the problem using nohup, but I thought there might be something more clever...

    – hayavuk
    Jan 13 '11 at 0:59






  • 1





    @foxbunny: nohup? Why simply someprocess | python script.py? Why involve nohup?

    – S.Lott
    Jan 13 '11 at 1:39






  • 3





    Rewrite the print statements to apply the logging module from the stdlib. Then you can redirect output everywhere, have control over how much output you want etc. In most cases production code should not print but log.

    – erikbwork
    Jan 3 '14 at 7:44






  • 2





    Perhaps a better solution for this problem is the screen command, which will save your bash session and allow you to access it from different runs.

    – Ryan Amos
    May 5 '14 at 23:08














  • 7





    That's not really a python thing, it's a shell function. Just run your script like script.p > file

    – Falmarri
    Jan 13 '11 at 0:52











  • I currently solve the problem using nohup, but I thought there might be something more clever...

    – hayavuk
    Jan 13 '11 at 0:59






  • 1





    @foxbunny: nohup? Why simply someprocess | python script.py? Why involve nohup?

    – S.Lott
    Jan 13 '11 at 1:39






  • 3





    Rewrite the print statements to apply the logging module from the stdlib. Then you can redirect output everywhere, have control over how much output you want etc. In most cases production code should not print but log.

    – erikbwork
    Jan 3 '14 at 7:44






  • 2





    Perhaps a better solution for this problem is the screen command, which will save your bash session and allow you to access it from different runs.

    – Ryan Amos
    May 5 '14 at 23:08








7




7





That's not really a python thing, it's a shell function. Just run your script like script.p > file

– Falmarri
Jan 13 '11 at 0:52





That's not really a python thing, it's a shell function. Just run your script like script.p > file

– Falmarri
Jan 13 '11 at 0:52













I currently solve the problem using nohup, but I thought there might be something more clever...

– hayavuk
Jan 13 '11 at 0:59





I currently solve the problem using nohup, but I thought there might be something more clever...

– hayavuk
Jan 13 '11 at 0:59




1




1





@foxbunny: nohup? Why simply someprocess | python script.py? Why involve nohup?

– S.Lott
Jan 13 '11 at 1:39





@foxbunny: nohup? Why simply someprocess | python script.py? Why involve nohup?

– S.Lott
Jan 13 '11 at 1:39




3




3





Rewrite the print statements to apply the logging module from the stdlib. Then you can redirect output everywhere, have control over how much output you want etc. In most cases production code should not print but log.

– erikbwork
Jan 3 '14 at 7:44





Rewrite the print statements to apply the logging module from the stdlib. Then you can redirect output everywhere, have control over how much output you want etc. In most cases production code should not print but log.

– erikbwork
Jan 3 '14 at 7:44




2




2





Perhaps a better solution for this problem is the screen command, which will save your bash session and allow you to access it from different runs.

– Ryan Amos
May 5 '14 at 23:08





Perhaps a better solution for this problem is the screen command, which will save your bash session and allow you to access it from different runs.

– Ryan Amos
May 5 '14 at 23:08












11 Answers
11






active

oldest

votes


















338














If you want to do the redirection within the Python script, set sys.stdout to an file object does the trick:



import sys
sys.stdout = open('file', 'w')
print('test')


A far more common method is to use shell redirection when executing (same on Windows and Linux):



$ python foo.py > file





share|improve this answer





















  • 3





    If you're on Windows watch out for Windows bug - Cannot redirect output when I run Python script on Windows using just script's name

    – Piotr Dobrogost
    Oct 4 '12 at 11:00






  • 5





    It doesn't work with from sys import stdout, maybe because it creates a local copy. Also you can use it with with, e.g. with open('file', 'w') as sys.stdout: functionThatPrints(). You can now implement functionThatPrints() using normal print statements.

    – mgold
    Dec 13 '12 at 0:07






  • 33





    It's best to keep a local copy, stdout = sys.stdout so you can put it back when you're done, sys.stdout = stdout. That way if you're being called from a function that uses print you don't screw them up.

    – mgold
    Dec 20 '12 at 15:06






  • 4





    @Jan: buffering=0 disables buffering (it may negatively affect performance (10-100 times)). buffering=1 enables line buffering so that you could use tail -f for a line-oriented output.

    – jfs
    Jul 31 '14 at 13:39






  • 29





    @mgold or you can use sys.stdout = sys.__stdout__ to get it back.

    – clemtoy
    Jul 9 '15 at 12:52



















136














There is contextlib.redirect_stdout() function in Python 3.4:



from contextlib import redirect_stdout

with open('help.txt', 'w') as f:
with redirect_stdout(f):
print('it now prints to `help.text`')


It is similar to:



import sys
from contextlib import contextmanager

@contextmanager
def redirect_stdout(new_target):
old_target, sys.stdout = sys.stdout, new_target # replace sys.stdout
try:
yield new_target # run some code with the replaced stdout
finally:
sys.stdout = old_target # restore to the previous value


that can be used on earlier Python versions. The latter version is not reusable. It can be made one if desired.



It doesn't redirect the stdout at the file descriptors level e.g.:



import os
from contextlib import redirect_stdout

stdout_fd = sys.stdout.fileno()
with open('output.txt', 'w') as f, redirect_stdout(f):
print('redirected to a file')
os.write(stdout_fd, b'not redirected')
os.system('echo this also is not redirected')


b'not redirected' and 'echo this also is not redirected' are not redirected to the output.txt file.



To redirect at the file descriptor level, os.dup2() could be used:



import os
import sys
from contextlib import contextmanager

def fileno(file_or_fd):
fd = getattr(file_or_fd, 'fileno', lambda: file_or_fd)()
if not isinstance(fd, int):
raise ValueError("Expected a file (`.fileno()`) or a file descriptor")
return fd

@contextmanager
def stdout_redirected(to=os.devnull, stdout=None):
if stdout is None:
stdout = sys.stdout

stdout_fd = fileno(stdout)
# copy stdout_fd before it is overwritten
#NOTE: `copied` is inheritable on Windows when duplicating a standard stream
with os.fdopen(os.dup(stdout_fd), 'wb') as copied:
stdout.flush() # flush library buffers that dup2 knows nothing about
try:
os.dup2(fileno(to), stdout_fd) # $ exec >&to
except ValueError: # filename
with open(to, 'wb') as to_file:
os.dup2(to_file.fileno(), stdout_fd) # $ exec > to
try:
yield stdout # allow code to be run with the redirected stdout
finally:
# restore stdout to its previous value
#NOTE: dup2 makes stdout_fd inheritable unconditionally
stdout.flush()
os.dup2(copied.fileno(), stdout_fd) # $ exec >&copied


The same example works now if stdout_redirected() is used instead of redirect_stdout():



import os
import sys

stdout_fd = sys.stdout.fileno()
with open('output.txt', 'w') as f, stdout_redirected(f):
print('redirected to a file')
os.write(stdout_fd, b'it is redirected nown')
os.system('echo this is also redirected')
print('this is goes back to stdout')


The output that previously was printed on stdout now goes to output.txt as long as stdout_redirected() context manager is active.



Note: stdout.flush() does not flush
C stdio buffers on Python 3 where I/O is implemented directly on read()/write() system calls. To flush all open C stdio output streams, you could call libc.fflush(None) explicitly if some C extension uses stdio-based I/O:



try:
import ctypes
from ctypes.util import find_library
except ImportError:
libc = None
else:
try:
libc = ctypes.cdll.msvcrt # Windows
except OSError:
libc = ctypes.cdll.LoadLibrary(find_library('c'))

def flush(stream):
try:
libc.fflush(None)
stream.flush()
except (AttributeError, ValueError, IOError):
pass # unsupported


You could use stdout parameter to redirect other streams, not only sys.stdout e.g., to merge sys.stderr and sys.stdout:



def merged_stderr_stdout():  # $ exec 2>&1
return stdout_redirected(to=sys.stdout, stdout=sys.stderr)


Example:



from __future__ import print_function
import sys

with merged_stderr_stdout():
print('this is printed on stdout')
print('this is also printed on stdout', file=sys.stderr)


Note: stdout_redirected() mixes buffered I/O (sys.stdout usually) and unbuffered I/O (operations on file descriptors directly). Beware, there could be buffering issues.



To answer, your edit: you could use python-daemon to daemonize your script and use logging module (as @erikb85 suggested) instead of print statements and merely redirecting stdout for your long-running Python script that you run using nohup now.






share|improve this answer





















  • 3





    stdout_redirected is helpful. Be aware this doesn't work inside doctests, since the special SpoofOut handler doctest uses to replace sys.stdout doesn't have a fileno attribute.

    – Chris Johnson
    Apr 21 '14 at 15:47











  • @ChrisJohnson: If it doesn't raise ValueError("Expected a file (`.fileno()`) or a file descriptor") then it is a bug. Are you sure it doesn't raise it?

    – jfs
    Apr 21 '14 at 16:37













  • It does raise that error, which is what make it not usable within a doctest. To use your function within a doctest, it appears necessary to specify doctest.sys.__stdout__ where we would normally use sys.stdout. This isn't a problem with your function, just an accommodation required for doctest since it replaces stdout with an object that doesn't have all the attributes a true file would.

    – Chris Johnson
    Apr 21 '14 at 19:42













  • stdout_redirected() has stdout parameter, you could set it to sys.__stdout__ if you want to redirect the original python stdout (that should have a valid .fileno() in most cases). It does nothing for the current sys.stdout if they are different. Don't use doctest.sys; it is available by accident.

    – jfs
    Apr 21 '14 at 19:48













  • This really works well, i.e. redirect stdout and stderr to a fd: with stdout_redirected(to=fd): with merged_stderr_stdout(): print('...'); print('...', file=sys.stderr)

    – neok
    Sep 19 '16 at 8:36





















87














you can try this too much better



import sys

class Logger(object):
def __init__(self, filename="Default.log"):
self.terminal = sys.stdout
self.log = open(filename, "a")

def write(self, message):
self.terminal.write(message)
self.log.write(message)

sys.stdout = Logger("yourlogfilename.txt")
print "Hello world !" # this is should be saved in yourlogfilename.txt





share|improve this answer


























  • Any suggestions for piping to logger or syslog?

    – dsummersl
    Mar 8 '13 at 17:08











  • If you want to edit a file this isn't very useful. Anyway +1 for the nice trick

    – aIKid
    Mar 20 '14 at 5:41






  • 7





    This will have consequences for code which assumes sys.stdout is a full fledged file object with methods such as fileno() (which includes code in the python standard library). I would add a __getattr__(self, attr) method to that which defers attribute lookup to self.terminal. def __getattr__(self, attr): return getattr(self.terminal, attr)

    – peabody
    Jul 22 '14 at 22:39








  • 3





    You have to add def flush(self): method as well to class Logger.

    – loretoparisi
    Aug 3 '17 at 14:13











  • This helped me setup logging to both stdout and a file: docs.python.org/3/howto/logging-cookbook.html

    – colllin
    Mar 15 '18 at 17:27



















29














The other answers didn't cover the case where you want forked processes to share your new stdout.



To do that:



from os import open, close, dup, O_WRONLY

old = dup(1)
close(1)
open("file", O_WRONLY) # should open on 1

..... do stuff and then restore

close(1)
dup(old) # should dup to 1
close(old) # get rid of left overs





share|improve this answer





















  • 3





    one needs to replace the 'w' attribute with, os.O_WRONLY|os.O_CREATE ... can't send strings into the "os" commands!

    – Ch'marr
    Jul 26 '12 at 21:52






  • 3





    Insert a sys.stdout.flush() before the close(1) statement to make sure the redirect 'file' file gets the output. Also, you can use a tempfile.mkstemp() file in place of 'file'. And be careful you don't have other threads running that can steal the os's first file handle after the os.close(1) but before the 'file' is opened to use the handle.

    – Alex Robinson
    Nov 1 '12 at 3:59








  • 2





    its os.O_WRONLY | os.O_CREAT ... there is no E on there.

    – Jeff Sheffield
    Jan 26 '14 at 5:16











  • +1. You could also use os.dup2() and wrap it into a context manager as shown in my answer

    – jfs
    Mar 16 '14 at 7:46













  • @Ch'marr It's O_CREAT, not O_CREATE.

    – quant_dev
    Nov 17 '16 at 9:51



















25














Quoted from PEP 343 -- The "with" Statement (added import statement):



Redirect stdout temporarily:



import sys
from contextlib import contextmanager
@contextmanager
def stdout_redirected(new_stdout):
save_stdout = sys.stdout
sys.stdout = new_stdout
try:
yield None
finally:
sys.stdout = save_stdout


Used as follows:



with open(filename, "w") as f:
with stdout_redirected(f):
print "Hello world"


This isn't thread-safe, of course, but neither is doing this same dance manually. In single-threaded programs (for example in scripts) it is a popular way of doing things.








share|improve this answer


























  • +1. Note: it doesn't work for subprocesses e.g., os.system('echo not redirected'). My answer shows how to redirect such output

    – jfs
    Mar 16 '14 at 7:43





















11














import sys
sys.stdout = open('stdout.txt', 'w')





share|improve this answer































    3














    You need a terminal multiplexer like either tmux or GNU screen



    I'm surprised that a small comment by Ryan Amos' to the original question is the only mention of a solution far preferable to all the others on offer, no matter how clever the python trickery may be and how many upvotes they've received. Further to Ryan's comment, tmux is a nice alternative to GNU screen.



    But the principle is the same: if you ever find yourself wanting to leave a terminal job running while you log-out, head to the cafe for a sandwich, pop to the bathroom, go home (etc) and then later, reconnect to your terminal session from anywhere or any computer as though you'd never been away, terminal multiplexers are the answer. Think of them as VNC or remote desktop for terminal sessions. Anything else is a workaround. As a bonus, when the boss and/or partner comes in and you inadvertently ctrl-w / cmd-w your terminal window instead of your browser window with its dodgy content, you won't have lost the last 18 hours-worth of processing!






    share|improve this answer





















    • 2





      while it is a good answer for the part of the question appeared after the edit; it does not answer the question in the title (most people come here from google for the title)

      – jfs
      Jul 15 '15 at 14:01











    • That's a fair point, and one I hadn't considered.

      – duncan
      Jul 15 '15 at 17:57











    • It looks like tmux has moved to tmux.github.io

      – Teepeemm
      Mar 3 '17 at 3:19



















    2














    Based on this answer: https://stackoverflow.com/a/5916874/1060344, here is another way I figured out which I use in one of my projects. For whatever you replace sys.stderr or sys.stdout with, you have to make sure that the replacement complies with file interface, especially if this is something you are doing because stderr/stdout are used in some other library that is not under your control. That library may be using other methods of file object.



    Check out this way where I still let everything go do stderr/stdout (or any file for that matter) and also send the message to a log file using Python's logging facility (but you can really do anything with this):



    class FileToLogInterface(file):
    '''
    Interface to make sure that everytime anything is written to stderr, it is
    also forwarded to a file.
    '''

    def __init__(self, *args, **kwargs):
    if 'cfg' not in kwargs:
    raise TypeError('argument cfg is required.')
    else:
    if not isinstance(kwargs['cfg'], config.Config):
    raise TypeError(
    'argument cfg should be a valid '
    'PostSegmentation configuration object i.e. '
    'postsegmentation.config.Config')
    self._cfg = kwargs['cfg']
    kwargs.pop('cfg')

    self._logger = logging.getlogger('access_log')

    super(FileToLogInterface, self).__init__(*args, **kwargs)

    def write(self, msg):
    super(FileToLogInterface, self).write(msg)
    self._logger.info(msg)





    share|improve this answer

































      1














      Programs written in other languages (e.g. C) have to do special magic (called double-forking) expressly to detach from the terminal (and to prevent zombie processes). So, I think the best solution is to emulate them.



      A plus of re-executing your program is, you can choose redirections on the command-line, e.g. /usr/bin/python mycoolscript.py 2>&1 1>/dev/null



      See this post for more info: What is the reason for performing a double fork when creating a daemon?






      share|improve this answer


























      • Eh... can't say I'm a fan of processes managing their own double-forking. It's so common an idiom, and so easy to code wrong if you aren't careful. Better to write your process to run in the foreground, and use a system background task manager (systemd, upstart) or other utility (daemon(1)) to handle the forking boilerplate.

        – Lucretiel
        Dec 2 '14 at 5:09



















      0














      @marcog



      The second option is only good if script get excuted in a go .Or script should get executed completely only then the output goes into that file And infinite loops should`nt be present(optimally). Best solution if it is a simple script.






      share|improve this answer

































        -1














        Here is a variation of Yuda Prawira answer:




        • implement flush() and all the file attributes

        • write it as a contextmanager

        • capture stderr also


        .



        import contextlib, sys

        @contextlib.contextmanager
        def log_print(file):
        # capture all outputs to a log file while still printing it
        class Logger:
        def __init__(self, file):
        self.terminal = sys.stdout
        self.log = file

        def write(self, message):
        self.terminal.write(message)
        self.log.write(message)

        def __getattr__(self, attr):
        return getattr(self.terminal, attr)

        logger = Logger(file)

        _stdout = sys.stdout
        _stderr = sys.stderr
        sys.stdout = logger
        sys.stderr = logger
        try:
        yield logger.log
        finally:
        sys.stdout = _stdout
        sys.stderr = _stderr


        with log_print(open('mylogfile.log', 'w')):
        print('hello world')
        print('hello world on stderr', file=sys.stderr)

        # you can capture the output to a string with:
        # with log_print(io.StringIO()) as log:
        # ....
        # print('[captured output]', log.getvalue())





        share|improve this answer
































          11 Answers
          11






          active

          oldest

          votes








          11 Answers
          11






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          338














          If you want to do the redirection within the Python script, set sys.stdout to an file object does the trick:



          import sys
          sys.stdout = open('file', 'w')
          print('test')


          A far more common method is to use shell redirection when executing (same on Windows and Linux):



          $ python foo.py > file





          share|improve this answer





















          • 3





            If you're on Windows watch out for Windows bug - Cannot redirect output when I run Python script on Windows using just script's name

            – Piotr Dobrogost
            Oct 4 '12 at 11:00






          • 5





            It doesn't work with from sys import stdout, maybe because it creates a local copy. Also you can use it with with, e.g. with open('file', 'w') as sys.stdout: functionThatPrints(). You can now implement functionThatPrints() using normal print statements.

            – mgold
            Dec 13 '12 at 0:07






          • 33





            It's best to keep a local copy, stdout = sys.stdout so you can put it back when you're done, sys.stdout = stdout. That way if you're being called from a function that uses print you don't screw them up.

            – mgold
            Dec 20 '12 at 15:06






          • 4





            @Jan: buffering=0 disables buffering (it may negatively affect performance (10-100 times)). buffering=1 enables line buffering so that you could use tail -f for a line-oriented output.

            – jfs
            Jul 31 '14 at 13:39






          • 29





            @mgold or you can use sys.stdout = sys.__stdout__ to get it back.

            – clemtoy
            Jul 9 '15 at 12:52
















          338














          If you want to do the redirection within the Python script, set sys.stdout to an file object does the trick:



          import sys
          sys.stdout = open('file', 'w')
          print('test')


          A far more common method is to use shell redirection when executing (same on Windows and Linux):



          $ python foo.py > file





          share|improve this answer





















          • 3





            If you're on Windows watch out for Windows bug - Cannot redirect output when I run Python script on Windows using just script's name

            – Piotr Dobrogost
            Oct 4 '12 at 11:00






          • 5





            It doesn't work with from sys import stdout, maybe because it creates a local copy. Also you can use it with with, e.g. with open('file', 'w') as sys.stdout: functionThatPrints(). You can now implement functionThatPrints() using normal print statements.

            – mgold
            Dec 13 '12 at 0:07






          • 33





            It's best to keep a local copy, stdout = sys.stdout so you can put it back when you're done, sys.stdout = stdout. That way if you're being called from a function that uses print you don't screw them up.

            – mgold
            Dec 20 '12 at 15:06






          • 4





            @Jan: buffering=0 disables buffering (it may negatively affect performance (10-100 times)). buffering=1 enables line buffering so that you could use tail -f for a line-oriented output.

            – jfs
            Jul 31 '14 at 13:39






          • 29





            @mgold or you can use sys.stdout = sys.__stdout__ to get it back.

            – clemtoy
            Jul 9 '15 at 12:52














          338












          338








          338







          If you want to do the redirection within the Python script, set sys.stdout to an file object does the trick:



          import sys
          sys.stdout = open('file', 'w')
          print('test')


          A far more common method is to use shell redirection when executing (same on Windows and Linux):



          $ python foo.py > file





          share|improve this answer















          If you want to do the redirection within the Python script, set sys.stdout to an file object does the trick:



          import sys
          sys.stdout = open('file', 'w')
          print('test')


          A far more common method is to use shell redirection when executing (same on Windows and Linux):



          $ python foo.py > file






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Feb 6 at 1:50









          wordsforthewise

          3,67422952




          3,67422952










          answered Jan 13 '11 at 0:53









          marcogmarcog

          90.2k39173209




          90.2k39173209








          • 3





            If you're on Windows watch out for Windows bug - Cannot redirect output when I run Python script on Windows using just script's name

            – Piotr Dobrogost
            Oct 4 '12 at 11:00






          • 5





            It doesn't work with from sys import stdout, maybe because it creates a local copy. Also you can use it with with, e.g. with open('file', 'w') as sys.stdout: functionThatPrints(). You can now implement functionThatPrints() using normal print statements.

            – mgold
            Dec 13 '12 at 0:07






          • 33





            It's best to keep a local copy, stdout = sys.stdout so you can put it back when you're done, sys.stdout = stdout. That way if you're being called from a function that uses print you don't screw them up.

            – mgold
            Dec 20 '12 at 15:06






          • 4





            @Jan: buffering=0 disables buffering (it may negatively affect performance (10-100 times)). buffering=1 enables line buffering so that you could use tail -f for a line-oriented output.

            – jfs
            Jul 31 '14 at 13:39






          • 29





            @mgold or you can use sys.stdout = sys.__stdout__ to get it back.

            – clemtoy
            Jul 9 '15 at 12:52














          • 3





            If you're on Windows watch out for Windows bug - Cannot redirect output when I run Python script on Windows using just script's name

            – Piotr Dobrogost
            Oct 4 '12 at 11:00






          • 5





            It doesn't work with from sys import stdout, maybe because it creates a local copy. Also you can use it with with, e.g. with open('file', 'w') as sys.stdout: functionThatPrints(). You can now implement functionThatPrints() using normal print statements.

            – mgold
            Dec 13 '12 at 0:07






          • 33





            It's best to keep a local copy, stdout = sys.stdout so you can put it back when you're done, sys.stdout = stdout. That way if you're being called from a function that uses print you don't screw them up.

            – mgold
            Dec 20 '12 at 15:06






          • 4





            @Jan: buffering=0 disables buffering (it may negatively affect performance (10-100 times)). buffering=1 enables line buffering so that you could use tail -f for a line-oriented output.

            – jfs
            Jul 31 '14 at 13:39






          • 29





            @mgold or you can use sys.stdout = sys.__stdout__ to get it back.

            – clemtoy
            Jul 9 '15 at 12:52








          3




          3





          If you're on Windows watch out for Windows bug - Cannot redirect output when I run Python script on Windows using just script's name

          – Piotr Dobrogost
          Oct 4 '12 at 11:00





          If you're on Windows watch out for Windows bug - Cannot redirect output when I run Python script on Windows using just script's name

          – Piotr Dobrogost
          Oct 4 '12 at 11:00




          5




          5





          It doesn't work with from sys import stdout, maybe because it creates a local copy. Also you can use it with with, e.g. with open('file', 'w') as sys.stdout: functionThatPrints(). You can now implement functionThatPrints() using normal print statements.

          – mgold
          Dec 13 '12 at 0:07





          It doesn't work with from sys import stdout, maybe because it creates a local copy. Also you can use it with with, e.g. with open('file', 'w') as sys.stdout: functionThatPrints(). You can now implement functionThatPrints() using normal print statements.

          – mgold
          Dec 13 '12 at 0:07




          33




          33





          It's best to keep a local copy, stdout = sys.stdout so you can put it back when you're done, sys.stdout = stdout. That way if you're being called from a function that uses print you don't screw them up.

          – mgold
          Dec 20 '12 at 15:06





          It's best to keep a local copy, stdout = sys.stdout so you can put it back when you're done, sys.stdout = stdout. That way if you're being called from a function that uses print you don't screw them up.

          – mgold
          Dec 20 '12 at 15:06




          4




          4





          @Jan: buffering=0 disables buffering (it may negatively affect performance (10-100 times)). buffering=1 enables line buffering so that you could use tail -f for a line-oriented output.

          – jfs
          Jul 31 '14 at 13:39





          @Jan: buffering=0 disables buffering (it may negatively affect performance (10-100 times)). buffering=1 enables line buffering so that you could use tail -f for a line-oriented output.

          – jfs
          Jul 31 '14 at 13:39




          29




          29





          @mgold or you can use sys.stdout = sys.__stdout__ to get it back.

          – clemtoy
          Jul 9 '15 at 12:52





          @mgold or you can use sys.stdout = sys.__stdout__ to get it back.

          – clemtoy
          Jul 9 '15 at 12:52













          136














          There is contextlib.redirect_stdout() function in Python 3.4:



          from contextlib import redirect_stdout

          with open('help.txt', 'w') as f:
          with redirect_stdout(f):
          print('it now prints to `help.text`')


          It is similar to:



          import sys
          from contextlib import contextmanager

          @contextmanager
          def redirect_stdout(new_target):
          old_target, sys.stdout = sys.stdout, new_target # replace sys.stdout
          try:
          yield new_target # run some code with the replaced stdout
          finally:
          sys.stdout = old_target # restore to the previous value


          that can be used on earlier Python versions. The latter version is not reusable. It can be made one if desired.



          It doesn't redirect the stdout at the file descriptors level e.g.:



          import os
          from contextlib import redirect_stdout

          stdout_fd = sys.stdout.fileno()
          with open('output.txt', 'w') as f, redirect_stdout(f):
          print('redirected to a file')
          os.write(stdout_fd, b'not redirected')
          os.system('echo this also is not redirected')


          b'not redirected' and 'echo this also is not redirected' are not redirected to the output.txt file.



          To redirect at the file descriptor level, os.dup2() could be used:



          import os
          import sys
          from contextlib import contextmanager

          def fileno(file_or_fd):
          fd = getattr(file_or_fd, 'fileno', lambda: file_or_fd)()
          if not isinstance(fd, int):
          raise ValueError("Expected a file (`.fileno()`) or a file descriptor")
          return fd

          @contextmanager
          def stdout_redirected(to=os.devnull, stdout=None):
          if stdout is None:
          stdout = sys.stdout

          stdout_fd = fileno(stdout)
          # copy stdout_fd before it is overwritten
          #NOTE: `copied` is inheritable on Windows when duplicating a standard stream
          with os.fdopen(os.dup(stdout_fd), 'wb') as copied:
          stdout.flush() # flush library buffers that dup2 knows nothing about
          try:
          os.dup2(fileno(to), stdout_fd) # $ exec >&to
          except ValueError: # filename
          with open(to, 'wb') as to_file:
          os.dup2(to_file.fileno(), stdout_fd) # $ exec > to
          try:
          yield stdout # allow code to be run with the redirected stdout
          finally:
          # restore stdout to its previous value
          #NOTE: dup2 makes stdout_fd inheritable unconditionally
          stdout.flush()
          os.dup2(copied.fileno(), stdout_fd) # $ exec >&copied


          The same example works now if stdout_redirected() is used instead of redirect_stdout():



          import os
          import sys

          stdout_fd = sys.stdout.fileno()
          with open('output.txt', 'w') as f, stdout_redirected(f):
          print('redirected to a file')
          os.write(stdout_fd, b'it is redirected nown')
          os.system('echo this is also redirected')
          print('this is goes back to stdout')


          The output that previously was printed on stdout now goes to output.txt as long as stdout_redirected() context manager is active.



          Note: stdout.flush() does not flush
          C stdio buffers on Python 3 where I/O is implemented directly on read()/write() system calls. To flush all open C stdio output streams, you could call libc.fflush(None) explicitly if some C extension uses stdio-based I/O:



          try:
          import ctypes
          from ctypes.util import find_library
          except ImportError:
          libc = None
          else:
          try:
          libc = ctypes.cdll.msvcrt # Windows
          except OSError:
          libc = ctypes.cdll.LoadLibrary(find_library('c'))

          def flush(stream):
          try:
          libc.fflush(None)
          stream.flush()
          except (AttributeError, ValueError, IOError):
          pass # unsupported


          You could use stdout parameter to redirect other streams, not only sys.stdout e.g., to merge sys.stderr and sys.stdout:



          def merged_stderr_stdout():  # $ exec 2>&1
          return stdout_redirected(to=sys.stdout, stdout=sys.stderr)


          Example:



          from __future__ import print_function
          import sys

          with merged_stderr_stdout():
          print('this is printed on stdout')
          print('this is also printed on stdout', file=sys.stderr)


          Note: stdout_redirected() mixes buffered I/O (sys.stdout usually) and unbuffered I/O (operations on file descriptors directly). Beware, there could be buffering issues.



          To answer, your edit: you could use python-daemon to daemonize your script and use logging module (as @erikb85 suggested) instead of print statements and merely redirecting stdout for your long-running Python script that you run using nohup now.






          share|improve this answer





















          • 3





            stdout_redirected is helpful. Be aware this doesn't work inside doctests, since the special SpoofOut handler doctest uses to replace sys.stdout doesn't have a fileno attribute.

            – Chris Johnson
            Apr 21 '14 at 15:47











          • @ChrisJohnson: If it doesn't raise ValueError("Expected a file (`.fileno()`) or a file descriptor") then it is a bug. Are you sure it doesn't raise it?

            – jfs
            Apr 21 '14 at 16:37













          • It does raise that error, which is what make it not usable within a doctest. To use your function within a doctest, it appears necessary to specify doctest.sys.__stdout__ where we would normally use sys.stdout. This isn't a problem with your function, just an accommodation required for doctest since it replaces stdout with an object that doesn't have all the attributes a true file would.

            – Chris Johnson
            Apr 21 '14 at 19:42













          • stdout_redirected() has stdout parameter, you could set it to sys.__stdout__ if you want to redirect the original python stdout (that should have a valid .fileno() in most cases). It does nothing for the current sys.stdout if they are different. Don't use doctest.sys; it is available by accident.

            – jfs
            Apr 21 '14 at 19:48













          • This really works well, i.e. redirect stdout and stderr to a fd: with stdout_redirected(to=fd): with merged_stderr_stdout(): print('...'); print('...', file=sys.stderr)

            – neok
            Sep 19 '16 at 8:36


















          136














          There is contextlib.redirect_stdout() function in Python 3.4:



          from contextlib import redirect_stdout

          with open('help.txt', 'w') as f:
          with redirect_stdout(f):
          print('it now prints to `help.text`')


          It is similar to:



          import sys
          from contextlib import contextmanager

          @contextmanager
          def redirect_stdout(new_target):
          old_target, sys.stdout = sys.stdout, new_target # replace sys.stdout
          try:
          yield new_target # run some code with the replaced stdout
          finally:
          sys.stdout = old_target # restore to the previous value


          that can be used on earlier Python versions. The latter version is not reusable. It can be made one if desired.



          It doesn't redirect the stdout at the file descriptors level e.g.:



          import os
          from contextlib import redirect_stdout

          stdout_fd = sys.stdout.fileno()
          with open('output.txt', 'w') as f, redirect_stdout(f):
          print('redirected to a file')
          os.write(stdout_fd, b'not redirected')
          os.system('echo this also is not redirected')


          b'not redirected' and 'echo this also is not redirected' are not redirected to the output.txt file.



          To redirect at the file descriptor level, os.dup2() could be used:



          import os
          import sys
          from contextlib import contextmanager

          def fileno(file_or_fd):
          fd = getattr(file_or_fd, 'fileno', lambda: file_or_fd)()
          if not isinstance(fd, int):
          raise ValueError("Expected a file (`.fileno()`) or a file descriptor")
          return fd

          @contextmanager
          def stdout_redirected(to=os.devnull, stdout=None):
          if stdout is None:
          stdout = sys.stdout

          stdout_fd = fileno(stdout)
          # copy stdout_fd before it is overwritten
          #NOTE: `copied` is inheritable on Windows when duplicating a standard stream
          with os.fdopen(os.dup(stdout_fd), 'wb') as copied:
          stdout.flush() # flush library buffers that dup2 knows nothing about
          try:
          os.dup2(fileno(to), stdout_fd) # $ exec >&to
          except ValueError: # filename
          with open(to, 'wb') as to_file:
          os.dup2(to_file.fileno(), stdout_fd) # $ exec > to
          try:
          yield stdout # allow code to be run with the redirected stdout
          finally:
          # restore stdout to its previous value
          #NOTE: dup2 makes stdout_fd inheritable unconditionally
          stdout.flush()
          os.dup2(copied.fileno(), stdout_fd) # $ exec >&copied


          The same example works now if stdout_redirected() is used instead of redirect_stdout():



          import os
          import sys

          stdout_fd = sys.stdout.fileno()
          with open('output.txt', 'w') as f, stdout_redirected(f):
          print('redirected to a file')
          os.write(stdout_fd, b'it is redirected nown')
          os.system('echo this is also redirected')
          print('this is goes back to stdout')


          The output that previously was printed on stdout now goes to output.txt as long as stdout_redirected() context manager is active.



          Note: stdout.flush() does not flush
          C stdio buffers on Python 3 where I/O is implemented directly on read()/write() system calls. To flush all open C stdio output streams, you could call libc.fflush(None) explicitly if some C extension uses stdio-based I/O:



          try:
          import ctypes
          from ctypes.util import find_library
          except ImportError:
          libc = None
          else:
          try:
          libc = ctypes.cdll.msvcrt # Windows
          except OSError:
          libc = ctypes.cdll.LoadLibrary(find_library('c'))

          def flush(stream):
          try:
          libc.fflush(None)
          stream.flush()
          except (AttributeError, ValueError, IOError):
          pass # unsupported


          You could use stdout parameter to redirect other streams, not only sys.stdout e.g., to merge sys.stderr and sys.stdout:



          def merged_stderr_stdout():  # $ exec 2>&1
          return stdout_redirected(to=sys.stdout, stdout=sys.stderr)


          Example:



          from __future__ import print_function
          import sys

          with merged_stderr_stdout():
          print('this is printed on stdout')
          print('this is also printed on stdout', file=sys.stderr)


          Note: stdout_redirected() mixes buffered I/O (sys.stdout usually) and unbuffered I/O (operations on file descriptors directly). Beware, there could be buffering issues.



          To answer, your edit: you could use python-daemon to daemonize your script and use logging module (as @erikb85 suggested) instead of print statements and merely redirecting stdout for your long-running Python script that you run using nohup now.






          share|improve this answer





















          • 3





            stdout_redirected is helpful. Be aware this doesn't work inside doctests, since the special SpoofOut handler doctest uses to replace sys.stdout doesn't have a fileno attribute.

            – Chris Johnson
            Apr 21 '14 at 15:47











          • @ChrisJohnson: If it doesn't raise ValueError("Expected a file (`.fileno()`) or a file descriptor") then it is a bug. Are you sure it doesn't raise it?

            – jfs
            Apr 21 '14 at 16:37













          • It does raise that error, which is what make it not usable within a doctest. To use your function within a doctest, it appears necessary to specify doctest.sys.__stdout__ where we would normally use sys.stdout. This isn't a problem with your function, just an accommodation required for doctest since it replaces stdout with an object that doesn't have all the attributes a true file would.

            – Chris Johnson
            Apr 21 '14 at 19:42













          • stdout_redirected() has stdout parameter, you could set it to sys.__stdout__ if you want to redirect the original python stdout (that should have a valid .fileno() in most cases). It does nothing for the current sys.stdout if they are different. Don't use doctest.sys; it is available by accident.

            – jfs
            Apr 21 '14 at 19:48













          • This really works well, i.e. redirect stdout and stderr to a fd: with stdout_redirected(to=fd): with merged_stderr_stdout(): print('...'); print('...', file=sys.stderr)

            – neok
            Sep 19 '16 at 8:36
















          136












          136








          136







          There is contextlib.redirect_stdout() function in Python 3.4:



          from contextlib import redirect_stdout

          with open('help.txt', 'w') as f:
          with redirect_stdout(f):
          print('it now prints to `help.text`')


          It is similar to:



          import sys
          from contextlib import contextmanager

          @contextmanager
          def redirect_stdout(new_target):
          old_target, sys.stdout = sys.stdout, new_target # replace sys.stdout
          try:
          yield new_target # run some code with the replaced stdout
          finally:
          sys.stdout = old_target # restore to the previous value


          that can be used on earlier Python versions. The latter version is not reusable. It can be made one if desired.



          It doesn't redirect the stdout at the file descriptors level e.g.:



          import os
          from contextlib import redirect_stdout

          stdout_fd = sys.stdout.fileno()
          with open('output.txt', 'w') as f, redirect_stdout(f):
          print('redirected to a file')
          os.write(stdout_fd, b'not redirected')
          os.system('echo this also is not redirected')


          b'not redirected' and 'echo this also is not redirected' are not redirected to the output.txt file.



          To redirect at the file descriptor level, os.dup2() could be used:



          import os
          import sys
          from contextlib import contextmanager

          def fileno(file_or_fd):
          fd = getattr(file_or_fd, 'fileno', lambda: file_or_fd)()
          if not isinstance(fd, int):
          raise ValueError("Expected a file (`.fileno()`) or a file descriptor")
          return fd

          @contextmanager
          def stdout_redirected(to=os.devnull, stdout=None):
          if stdout is None:
          stdout = sys.stdout

          stdout_fd = fileno(stdout)
          # copy stdout_fd before it is overwritten
          #NOTE: `copied` is inheritable on Windows when duplicating a standard stream
          with os.fdopen(os.dup(stdout_fd), 'wb') as copied:
          stdout.flush() # flush library buffers that dup2 knows nothing about
          try:
          os.dup2(fileno(to), stdout_fd) # $ exec >&to
          except ValueError: # filename
          with open(to, 'wb') as to_file:
          os.dup2(to_file.fileno(), stdout_fd) # $ exec > to
          try:
          yield stdout # allow code to be run with the redirected stdout
          finally:
          # restore stdout to its previous value
          #NOTE: dup2 makes stdout_fd inheritable unconditionally
          stdout.flush()
          os.dup2(copied.fileno(), stdout_fd) # $ exec >&copied


          The same example works now if stdout_redirected() is used instead of redirect_stdout():



          import os
          import sys

          stdout_fd = sys.stdout.fileno()
          with open('output.txt', 'w') as f, stdout_redirected(f):
          print('redirected to a file')
          os.write(stdout_fd, b'it is redirected nown')
          os.system('echo this is also redirected')
          print('this is goes back to stdout')


          The output that previously was printed on stdout now goes to output.txt as long as stdout_redirected() context manager is active.



          Note: stdout.flush() does not flush
          C stdio buffers on Python 3 where I/O is implemented directly on read()/write() system calls. To flush all open C stdio output streams, you could call libc.fflush(None) explicitly if some C extension uses stdio-based I/O:



          try:
          import ctypes
          from ctypes.util import find_library
          except ImportError:
          libc = None
          else:
          try:
          libc = ctypes.cdll.msvcrt # Windows
          except OSError:
          libc = ctypes.cdll.LoadLibrary(find_library('c'))

          def flush(stream):
          try:
          libc.fflush(None)
          stream.flush()
          except (AttributeError, ValueError, IOError):
          pass # unsupported


          You could use stdout parameter to redirect other streams, not only sys.stdout e.g., to merge sys.stderr and sys.stdout:



          def merged_stderr_stdout():  # $ exec 2>&1
          return stdout_redirected(to=sys.stdout, stdout=sys.stderr)


          Example:



          from __future__ import print_function
          import sys

          with merged_stderr_stdout():
          print('this is printed on stdout')
          print('this is also printed on stdout', file=sys.stderr)


          Note: stdout_redirected() mixes buffered I/O (sys.stdout usually) and unbuffered I/O (operations on file descriptors directly). Beware, there could be buffering issues.



          To answer, your edit: you could use python-daemon to daemonize your script and use logging module (as @erikb85 suggested) instead of print statements and merely redirecting stdout for your long-running Python script that you run using nohup now.






          share|improve this answer















          There is contextlib.redirect_stdout() function in Python 3.4:



          from contextlib import redirect_stdout

          with open('help.txt', 'w') as f:
          with redirect_stdout(f):
          print('it now prints to `help.text`')


          It is similar to:



          import sys
          from contextlib import contextmanager

          @contextmanager
          def redirect_stdout(new_target):
          old_target, sys.stdout = sys.stdout, new_target # replace sys.stdout
          try:
          yield new_target # run some code with the replaced stdout
          finally:
          sys.stdout = old_target # restore to the previous value


          that can be used on earlier Python versions. The latter version is not reusable. It can be made one if desired.



          It doesn't redirect the stdout at the file descriptors level e.g.:



          import os
          from contextlib import redirect_stdout

          stdout_fd = sys.stdout.fileno()
          with open('output.txt', 'w') as f, redirect_stdout(f):
          print('redirected to a file')
          os.write(stdout_fd, b'not redirected')
          os.system('echo this also is not redirected')


          b'not redirected' and 'echo this also is not redirected' are not redirected to the output.txt file.



          To redirect at the file descriptor level, os.dup2() could be used:



          import os
          import sys
          from contextlib import contextmanager

          def fileno(file_or_fd):
          fd = getattr(file_or_fd, 'fileno', lambda: file_or_fd)()
          if not isinstance(fd, int):
          raise ValueError("Expected a file (`.fileno()`) or a file descriptor")
          return fd

          @contextmanager
          def stdout_redirected(to=os.devnull, stdout=None):
          if stdout is None:
          stdout = sys.stdout

          stdout_fd = fileno(stdout)
          # copy stdout_fd before it is overwritten
          #NOTE: `copied` is inheritable on Windows when duplicating a standard stream
          with os.fdopen(os.dup(stdout_fd), 'wb') as copied:
          stdout.flush() # flush library buffers that dup2 knows nothing about
          try:
          os.dup2(fileno(to), stdout_fd) # $ exec >&to
          except ValueError: # filename
          with open(to, 'wb') as to_file:
          os.dup2(to_file.fileno(), stdout_fd) # $ exec > to
          try:
          yield stdout # allow code to be run with the redirected stdout
          finally:
          # restore stdout to its previous value
          #NOTE: dup2 makes stdout_fd inheritable unconditionally
          stdout.flush()
          os.dup2(copied.fileno(), stdout_fd) # $ exec >&copied


          The same example works now if stdout_redirected() is used instead of redirect_stdout():



          import os
          import sys

          stdout_fd = sys.stdout.fileno()
          with open('output.txt', 'w') as f, stdout_redirected(f):
          print('redirected to a file')
          os.write(stdout_fd, b'it is redirected nown')
          os.system('echo this is also redirected')
          print('this is goes back to stdout')


          The output that previously was printed on stdout now goes to output.txt as long as stdout_redirected() context manager is active.



          Note: stdout.flush() does not flush
          C stdio buffers on Python 3 where I/O is implemented directly on read()/write() system calls. To flush all open C stdio output streams, you could call libc.fflush(None) explicitly if some C extension uses stdio-based I/O:



          try:
          import ctypes
          from ctypes.util import find_library
          except ImportError:
          libc = None
          else:
          try:
          libc = ctypes.cdll.msvcrt # Windows
          except OSError:
          libc = ctypes.cdll.LoadLibrary(find_library('c'))

          def flush(stream):
          try:
          libc.fflush(None)
          stream.flush()
          except (AttributeError, ValueError, IOError):
          pass # unsupported


          You could use stdout parameter to redirect other streams, not only sys.stdout e.g., to merge sys.stderr and sys.stdout:



          def merged_stderr_stdout():  # $ exec 2>&1
          return stdout_redirected(to=sys.stdout, stdout=sys.stderr)


          Example:



          from __future__ import print_function
          import sys

          with merged_stderr_stdout():
          print('this is printed on stdout')
          print('this is also printed on stdout', file=sys.stderr)


          Note: stdout_redirected() mixes buffered I/O (sys.stdout usually) and unbuffered I/O (operations on file descriptors directly). Beware, there could be buffering issues.



          To answer, your edit: you could use python-daemon to daemonize your script and use logging module (as @erikb85 suggested) instead of print statements and merely redirecting stdout for your long-running Python script that you run using nohup now.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited May 23 '17 at 12:26









          Community

          11




          11










          answered Mar 16 '14 at 7:39









          jfsjfs

          273k825791136




          273k825791136








          • 3





            stdout_redirected is helpful. Be aware this doesn't work inside doctests, since the special SpoofOut handler doctest uses to replace sys.stdout doesn't have a fileno attribute.

            – Chris Johnson
            Apr 21 '14 at 15:47











          • @ChrisJohnson: If it doesn't raise ValueError("Expected a file (`.fileno()`) or a file descriptor") then it is a bug. Are you sure it doesn't raise it?

            – jfs
            Apr 21 '14 at 16:37













          • It does raise that error, which is what make it not usable within a doctest. To use your function within a doctest, it appears necessary to specify doctest.sys.__stdout__ where we would normally use sys.stdout. This isn't a problem with your function, just an accommodation required for doctest since it replaces stdout with an object that doesn't have all the attributes a true file would.

            – Chris Johnson
            Apr 21 '14 at 19:42













          • stdout_redirected() has stdout parameter, you could set it to sys.__stdout__ if you want to redirect the original python stdout (that should have a valid .fileno() in most cases). It does nothing for the current sys.stdout if they are different. Don't use doctest.sys; it is available by accident.

            – jfs
            Apr 21 '14 at 19:48













          • This really works well, i.e. redirect stdout and stderr to a fd: with stdout_redirected(to=fd): with merged_stderr_stdout(): print('...'); print('...', file=sys.stderr)

            – neok
            Sep 19 '16 at 8:36
















          • 3





            stdout_redirected is helpful. Be aware this doesn't work inside doctests, since the special SpoofOut handler doctest uses to replace sys.stdout doesn't have a fileno attribute.

            – Chris Johnson
            Apr 21 '14 at 15:47











          • @ChrisJohnson: If it doesn't raise ValueError("Expected a file (`.fileno()`) or a file descriptor") then it is a bug. Are you sure it doesn't raise it?

            – jfs
            Apr 21 '14 at 16:37













          • It does raise that error, which is what make it not usable within a doctest. To use your function within a doctest, it appears necessary to specify doctest.sys.__stdout__ where we would normally use sys.stdout. This isn't a problem with your function, just an accommodation required for doctest since it replaces stdout with an object that doesn't have all the attributes a true file would.

            – Chris Johnson
            Apr 21 '14 at 19:42













          • stdout_redirected() has stdout parameter, you could set it to sys.__stdout__ if you want to redirect the original python stdout (that should have a valid .fileno() in most cases). It does nothing for the current sys.stdout if they are different. Don't use doctest.sys; it is available by accident.

            – jfs
            Apr 21 '14 at 19:48













          • This really works well, i.e. redirect stdout and stderr to a fd: with stdout_redirected(to=fd): with merged_stderr_stdout(): print('...'); print('...', file=sys.stderr)

            – neok
            Sep 19 '16 at 8:36










          3




          3





          stdout_redirected is helpful. Be aware this doesn't work inside doctests, since the special SpoofOut handler doctest uses to replace sys.stdout doesn't have a fileno attribute.

          – Chris Johnson
          Apr 21 '14 at 15:47





          stdout_redirected is helpful. Be aware this doesn't work inside doctests, since the special SpoofOut handler doctest uses to replace sys.stdout doesn't have a fileno attribute.

          – Chris Johnson
          Apr 21 '14 at 15:47













          @ChrisJohnson: If it doesn't raise ValueError("Expected a file (`.fileno()`) or a file descriptor") then it is a bug. Are you sure it doesn't raise it?

          – jfs
          Apr 21 '14 at 16:37







          @ChrisJohnson: If it doesn't raise ValueError("Expected a file (`.fileno()`) or a file descriptor") then it is a bug. Are you sure it doesn't raise it?

          – jfs
          Apr 21 '14 at 16:37















          It does raise that error, which is what make it not usable within a doctest. To use your function within a doctest, it appears necessary to specify doctest.sys.__stdout__ where we would normally use sys.stdout. This isn't a problem with your function, just an accommodation required for doctest since it replaces stdout with an object that doesn't have all the attributes a true file would.

          – Chris Johnson
          Apr 21 '14 at 19:42







          It does raise that error, which is what make it not usable within a doctest. To use your function within a doctest, it appears necessary to specify doctest.sys.__stdout__ where we would normally use sys.stdout. This isn't a problem with your function, just an accommodation required for doctest since it replaces stdout with an object that doesn't have all the attributes a true file would.

          – Chris Johnson
          Apr 21 '14 at 19:42















          stdout_redirected() has stdout parameter, you could set it to sys.__stdout__ if you want to redirect the original python stdout (that should have a valid .fileno() in most cases). It does nothing for the current sys.stdout if they are different. Don't use doctest.sys; it is available by accident.

          – jfs
          Apr 21 '14 at 19:48







          stdout_redirected() has stdout parameter, you could set it to sys.__stdout__ if you want to redirect the original python stdout (that should have a valid .fileno() in most cases). It does nothing for the current sys.stdout if they are different. Don't use doctest.sys; it is available by accident.

          – jfs
          Apr 21 '14 at 19:48















          This really works well, i.e. redirect stdout and stderr to a fd: with stdout_redirected(to=fd): with merged_stderr_stdout(): print('...'); print('...', file=sys.stderr)

          – neok
          Sep 19 '16 at 8:36







          This really works well, i.e. redirect stdout and stderr to a fd: with stdout_redirected(to=fd): with merged_stderr_stdout(): print('...'); print('...', file=sys.stderr)

          – neok
          Sep 19 '16 at 8:36













          87














          you can try this too much better



          import sys

          class Logger(object):
          def __init__(self, filename="Default.log"):
          self.terminal = sys.stdout
          self.log = open(filename, "a")

          def write(self, message):
          self.terminal.write(message)
          self.log.write(message)

          sys.stdout = Logger("yourlogfilename.txt")
          print "Hello world !" # this is should be saved in yourlogfilename.txt





          share|improve this answer


























          • Any suggestions for piping to logger or syslog?

            – dsummersl
            Mar 8 '13 at 17:08











          • If you want to edit a file this isn't very useful. Anyway +1 for the nice trick

            – aIKid
            Mar 20 '14 at 5:41






          • 7





            This will have consequences for code which assumes sys.stdout is a full fledged file object with methods such as fileno() (which includes code in the python standard library). I would add a __getattr__(self, attr) method to that which defers attribute lookup to self.terminal. def __getattr__(self, attr): return getattr(self.terminal, attr)

            – peabody
            Jul 22 '14 at 22:39








          • 3





            You have to add def flush(self): method as well to class Logger.

            – loretoparisi
            Aug 3 '17 at 14:13











          • This helped me setup logging to both stdout and a file: docs.python.org/3/howto/logging-cookbook.html

            – colllin
            Mar 15 '18 at 17:27
















          87














          you can try this too much better



          import sys

          class Logger(object):
          def __init__(self, filename="Default.log"):
          self.terminal = sys.stdout
          self.log = open(filename, "a")

          def write(self, message):
          self.terminal.write(message)
          self.log.write(message)

          sys.stdout = Logger("yourlogfilename.txt")
          print "Hello world !" # this is should be saved in yourlogfilename.txt





          share|improve this answer


























          • Any suggestions for piping to logger or syslog?

            – dsummersl
            Mar 8 '13 at 17:08











          • If you want to edit a file this isn't very useful. Anyway +1 for the nice trick

            – aIKid
            Mar 20 '14 at 5:41






          • 7





            This will have consequences for code which assumes sys.stdout is a full fledged file object with methods such as fileno() (which includes code in the python standard library). I would add a __getattr__(self, attr) method to that which defers attribute lookup to self.terminal. def __getattr__(self, attr): return getattr(self.terminal, attr)

            – peabody
            Jul 22 '14 at 22:39








          • 3





            You have to add def flush(self): method as well to class Logger.

            – loretoparisi
            Aug 3 '17 at 14:13











          • This helped me setup logging to both stdout and a file: docs.python.org/3/howto/logging-cookbook.html

            – colllin
            Mar 15 '18 at 17:27














          87












          87








          87







          you can try this too much better



          import sys

          class Logger(object):
          def __init__(self, filename="Default.log"):
          self.terminal = sys.stdout
          self.log = open(filename, "a")

          def write(self, message):
          self.terminal.write(message)
          self.log.write(message)

          sys.stdout = Logger("yourlogfilename.txt")
          print "Hello world !" # this is should be saved in yourlogfilename.txt





          share|improve this answer















          you can try this too much better



          import sys

          class Logger(object):
          def __init__(self, filename="Default.log"):
          self.terminal = sys.stdout
          self.log = open(filename, "a")

          def write(self, message):
          self.terminal.write(message)
          self.log.write(message)

          sys.stdout = Logger("yourlogfilename.txt")
          print "Hello world !" # this is should be saved in yourlogfilename.txt






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited May 10 '13 at 0:35









          Oleksiy

          4,30212844




          4,30212844










          answered May 6 '11 at 20:49









          Yuda PrawiraYuda Prawira

          6,41273447




          6,41273447













          • Any suggestions for piping to logger or syslog?

            – dsummersl
            Mar 8 '13 at 17:08











          • If you want to edit a file this isn't very useful. Anyway +1 for the nice trick

            – aIKid
            Mar 20 '14 at 5:41






          • 7





            This will have consequences for code which assumes sys.stdout is a full fledged file object with methods such as fileno() (which includes code in the python standard library). I would add a __getattr__(self, attr) method to that which defers attribute lookup to self.terminal. def __getattr__(self, attr): return getattr(self.terminal, attr)

            – peabody
            Jul 22 '14 at 22:39








          • 3





            You have to add def flush(self): method as well to class Logger.

            – loretoparisi
            Aug 3 '17 at 14:13











          • This helped me setup logging to both stdout and a file: docs.python.org/3/howto/logging-cookbook.html

            – colllin
            Mar 15 '18 at 17:27



















          • Any suggestions for piping to logger or syslog?

            – dsummersl
            Mar 8 '13 at 17:08











          • If you want to edit a file this isn't very useful. Anyway +1 for the nice trick

            – aIKid
            Mar 20 '14 at 5:41






          • 7





            This will have consequences for code which assumes sys.stdout is a full fledged file object with methods such as fileno() (which includes code in the python standard library). I would add a __getattr__(self, attr) method to that which defers attribute lookup to self.terminal. def __getattr__(self, attr): return getattr(self.terminal, attr)

            – peabody
            Jul 22 '14 at 22:39








          • 3





            You have to add def flush(self): method as well to class Logger.

            – loretoparisi
            Aug 3 '17 at 14:13











          • This helped me setup logging to both stdout and a file: docs.python.org/3/howto/logging-cookbook.html

            – colllin
            Mar 15 '18 at 17:27

















          Any suggestions for piping to logger or syslog?

          – dsummersl
          Mar 8 '13 at 17:08





          Any suggestions for piping to logger or syslog?

          – dsummersl
          Mar 8 '13 at 17:08













          If you want to edit a file this isn't very useful. Anyway +1 for the nice trick

          – aIKid
          Mar 20 '14 at 5:41





          If you want to edit a file this isn't very useful. Anyway +1 for the nice trick

          – aIKid
          Mar 20 '14 at 5:41




          7




          7





          This will have consequences for code which assumes sys.stdout is a full fledged file object with methods such as fileno() (which includes code in the python standard library). I would add a __getattr__(self, attr) method to that which defers attribute lookup to self.terminal. def __getattr__(self, attr): return getattr(self.terminal, attr)

          – peabody
          Jul 22 '14 at 22:39







          This will have consequences for code which assumes sys.stdout is a full fledged file object with methods such as fileno() (which includes code in the python standard library). I would add a __getattr__(self, attr) method to that which defers attribute lookup to self.terminal. def __getattr__(self, attr): return getattr(self.terminal, attr)

          – peabody
          Jul 22 '14 at 22:39






          3




          3





          You have to add def flush(self): method as well to class Logger.

          – loretoparisi
          Aug 3 '17 at 14:13





          You have to add def flush(self): method as well to class Logger.

          – loretoparisi
          Aug 3 '17 at 14:13













          This helped me setup logging to both stdout and a file: docs.python.org/3/howto/logging-cookbook.html

          – colllin
          Mar 15 '18 at 17:27





          This helped me setup logging to both stdout and a file: docs.python.org/3/howto/logging-cookbook.html

          – colllin
          Mar 15 '18 at 17:27











          29














          The other answers didn't cover the case where you want forked processes to share your new stdout.



          To do that:



          from os import open, close, dup, O_WRONLY

          old = dup(1)
          close(1)
          open("file", O_WRONLY) # should open on 1

          ..... do stuff and then restore

          close(1)
          dup(old) # should dup to 1
          close(old) # get rid of left overs





          share|improve this answer





















          • 3





            one needs to replace the 'w' attribute with, os.O_WRONLY|os.O_CREATE ... can't send strings into the "os" commands!

            – Ch'marr
            Jul 26 '12 at 21:52






          • 3





            Insert a sys.stdout.flush() before the close(1) statement to make sure the redirect 'file' file gets the output. Also, you can use a tempfile.mkstemp() file in place of 'file'. And be careful you don't have other threads running that can steal the os's first file handle after the os.close(1) but before the 'file' is opened to use the handle.

            – Alex Robinson
            Nov 1 '12 at 3:59








          • 2





            its os.O_WRONLY | os.O_CREAT ... there is no E on there.

            – Jeff Sheffield
            Jan 26 '14 at 5:16











          • +1. You could also use os.dup2() and wrap it into a context manager as shown in my answer

            – jfs
            Mar 16 '14 at 7:46













          • @Ch'marr It's O_CREAT, not O_CREATE.

            – quant_dev
            Nov 17 '16 at 9:51
















          29














          The other answers didn't cover the case where you want forked processes to share your new stdout.



          To do that:



          from os import open, close, dup, O_WRONLY

          old = dup(1)
          close(1)
          open("file", O_WRONLY) # should open on 1

          ..... do stuff and then restore

          close(1)
          dup(old) # should dup to 1
          close(old) # get rid of left overs





          share|improve this answer





















          • 3





            one needs to replace the 'w' attribute with, os.O_WRONLY|os.O_CREATE ... can't send strings into the "os" commands!

            – Ch'marr
            Jul 26 '12 at 21:52






          • 3





            Insert a sys.stdout.flush() before the close(1) statement to make sure the redirect 'file' file gets the output. Also, you can use a tempfile.mkstemp() file in place of 'file'. And be careful you don't have other threads running that can steal the os's first file handle after the os.close(1) but before the 'file' is opened to use the handle.

            – Alex Robinson
            Nov 1 '12 at 3:59








          • 2





            its os.O_WRONLY | os.O_CREAT ... there is no E on there.

            – Jeff Sheffield
            Jan 26 '14 at 5:16











          • +1. You could also use os.dup2() and wrap it into a context manager as shown in my answer

            – jfs
            Mar 16 '14 at 7:46













          • @Ch'marr It's O_CREAT, not O_CREATE.

            – quant_dev
            Nov 17 '16 at 9:51














          29












          29








          29







          The other answers didn't cover the case where you want forked processes to share your new stdout.



          To do that:



          from os import open, close, dup, O_WRONLY

          old = dup(1)
          close(1)
          open("file", O_WRONLY) # should open on 1

          ..... do stuff and then restore

          close(1)
          dup(old) # should dup to 1
          close(old) # get rid of left overs





          share|improve this answer















          The other answers didn't cover the case where you want forked processes to share your new stdout.



          To do that:



          from os import open, close, dup, O_WRONLY

          old = dup(1)
          close(1)
          open("file", O_WRONLY) # should open on 1

          ..... do stuff and then restore

          close(1)
          dup(old) # should dup to 1
          close(old) # get rid of left overs






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Mar 15 '14 at 0:04









          Thomas

          6,89542032




          6,89542032










          answered Jul 24 '12 at 14:24









          Yam MarcovicYam Marcovic

          6,5422036




          6,5422036








          • 3





            one needs to replace the 'w' attribute with, os.O_WRONLY|os.O_CREATE ... can't send strings into the "os" commands!

            – Ch'marr
            Jul 26 '12 at 21:52






          • 3





            Insert a sys.stdout.flush() before the close(1) statement to make sure the redirect 'file' file gets the output. Also, you can use a tempfile.mkstemp() file in place of 'file'. And be careful you don't have other threads running that can steal the os's first file handle after the os.close(1) but before the 'file' is opened to use the handle.

            – Alex Robinson
            Nov 1 '12 at 3:59








          • 2





            its os.O_WRONLY | os.O_CREAT ... there is no E on there.

            – Jeff Sheffield
            Jan 26 '14 at 5:16











          • +1. You could also use os.dup2() and wrap it into a context manager as shown in my answer

            – jfs
            Mar 16 '14 at 7:46













          • @Ch'marr It's O_CREAT, not O_CREATE.

            – quant_dev
            Nov 17 '16 at 9:51














          • 3





            one needs to replace the 'w' attribute with, os.O_WRONLY|os.O_CREATE ... can't send strings into the "os" commands!

            – Ch'marr
            Jul 26 '12 at 21:52






          • 3





            Insert a sys.stdout.flush() before the close(1) statement to make sure the redirect 'file' file gets the output. Also, you can use a tempfile.mkstemp() file in place of 'file'. And be careful you don't have other threads running that can steal the os's first file handle after the os.close(1) but before the 'file' is opened to use the handle.

            – Alex Robinson
            Nov 1 '12 at 3:59








          • 2





            its os.O_WRONLY | os.O_CREAT ... there is no E on there.

            – Jeff Sheffield
            Jan 26 '14 at 5:16











          • +1. You could also use os.dup2() and wrap it into a context manager as shown in my answer

            – jfs
            Mar 16 '14 at 7:46













          • @Ch'marr It's O_CREAT, not O_CREATE.

            – quant_dev
            Nov 17 '16 at 9:51








          3




          3





          one needs to replace the 'w' attribute with, os.O_WRONLY|os.O_CREATE ... can't send strings into the "os" commands!

          – Ch'marr
          Jul 26 '12 at 21:52





          one needs to replace the 'w' attribute with, os.O_WRONLY|os.O_CREATE ... can't send strings into the "os" commands!

          – Ch'marr
          Jul 26 '12 at 21:52




          3




          3





          Insert a sys.stdout.flush() before the close(1) statement to make sure the redirect 'file' file gets the output. Also, you can use a tempfile.mkstemp() file in place of 'file'. And be careful you don't have other threads running that can steal the os's first file handle after the os.close(1) but before the 'file' is opened to use the handle.

          – Alex Robinson
          Nov 1 '12 at 3:59







          Insert a sys.stdout.flush() before the close(1) statement to make sure the redirect 'file' file gets the output. Also, you can use a tempfile.mkstemp() file in place of 'file'. And be careful you don't have other threads running that can steal the os's first file handle after the os.close(1) but before the 'file' is opened to use the handle.

          – Alex Robinson
          Nov 1 '12 at 3:59






          2




          2





          its os.O_WRONLY | os.O_CREAT ... there is no E on there.

          – Jeff Sheffield
          Jan 26 '14 at 5:16





          its os.O_WRONLY | os.O_CREAT ... there is no E on there.

          – Jeff Sheffield
          Jan 26 '14 at 5:16













          +1. You could also use os.dup2() and wrap it into a context manager as shown in my answer

          – jfs
          Mar 16 '14 at 7:46







          +1. You could also use os.dup2() and wrap it into a context manager as shown in my answer

          – jfs
          Mar 16 '14 at 7:46















          @Ch'marr It's O_CREAT, not O_CREATE.

          – quant_dev
          Nov 17 '16 at 9:51





          @Ch'marr It's O_CREAT, not O_CREATE.

          – quant_dev
          Nov 17 '16 at 9:51











          25














          Quoted from PEP 343 -- The "with" Statement (added import statement):



          Redirect stdout temporarily:



          import sys
          from contextlib import contextmanager
          @contextmanager
          def stdout_redirected(new_stdout):
          save_stdout = sys.stdout
          sys.stdout = new_stdout
          try:
          yield None
          finally:
          sys.stdout = save_stdout


          Used as follows:



          with open(filename, "w") as f:
          with stdout_redirected(f):
          print "Hello world"


          This isn't thread-safe, of course, but neither is doing this same dance manually. In single-threaded programs (for example in scripts) it is a popular way of doing things.








          share|improve this answer


























          • +1. Note: it doesn't work for subprocesses e.g., os.system('echo not redirected'). My answer shows how to redirect such output

            – jfs
            Mar 16 '14 at 7:43


















          25














          Quoted from PEP 343 -- The "with" Statement (added import statement):



          Redirect stdout temporarily:



          import sys
          from contextlib import contextmanager
          @contextmanager
          def stdout_redirected(new_stdout):
          save_stdout = sys.stdout
          sys.stdout = new_stdout
          try:
          yield None
          finally:
          sys.stdout = save_stdout


          Used as follows:



          with open(filename, "w") as f:
          with stdout_redirected(f):
          print "Hello world"


          This isn't thread-safe, of course, but neither is doing this same dance manually. In single-threaded programs (for example in scripts) it is a popular way of doing things.








          share|improve this answer


























          • +1. Note: it doesn't work for subprocesses e.g., os.system('echo not redirected'). My answer shows how to redirect such output

            – jfs
            Mar 16 '14 at 7:43
















          25












          25








          25







          Quoted from PEP 343 -- The "with" Statement (added import statement):



          Redirect stdout temporarily:



          import sys
          from contextlib import contextmanager
          @contextmanager
          def stdout_redirected(new_stdout):
          save_stdout = sys.stdout
          sys.stdout = new_stdout
          try:
          yield None
          finally:
          sys.stdout = save_stdout


          Used as follows:



          with open(filename, "w") as f:
          with stdout_redirected(f):
          print "Hello world"


          This isn't thread-safe, of course, but neither is doing this same dance manually. In single-threaded programs (for example in scripts) it is a popular way of doing things.








          share|improve this answer















          Quoted from PEP 343 -- The "with" Statement (added import statement):



          Redirect stdout temporarily:



          import sys
          from contextlib import contextmanager
          @contextmanager
          def stdout_redirected(new_stdout):
          save_stdout = sys.stdout
          sys.stdout = new_stdout
          try:
          yield None
          finally:
          sys.stdout = save_stdout


          Used as follows:



          with open(filename, "w") as f:
          with stdout_redirected(f):
          print "Hello world"


          This isn't thread-safe, of course, but neither is doing this same dance manually. In single-threaded programs (for example in scripts) it is a popular way of doing things.









          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jun 6 '18 at 13:07









          Georgy

          2,34241729




          2,34241729










          answered Feb 5 '13 at 12:09









          GerliGerli

          35146




          35146













          • +1. Note: it doesn't work for subprocesses e.g., os.system('echo not redirected'). My answer shows how to redirect such output

            – jfs
            Mar 16 '14 at 7:43





















          • +1. Note: it doesn't work for subprocesses e.g., os.system('echo not redirected'). My answer shows how to redirect such output

            – jfs
            Mar 16 '14 at 7:43



















          +1. Note: it doesn't work for subprocesses e.g., os.system('echo not redirected'). My answer shows how to redirect such output

          – jfs
          Mar 16 '14 at 7:43







          +1. Note: it doesn't work for subprocesses e.g., os.system('echo not redirected'). My answer shows how to redirect such output

          – jfs
          Mar 16 '14 at 7:43













          11














          import sys
          sys.stdout = open('stdout.txt', 'w')





          share|improve this answer




























            11














            import sys
            sys.stdout = open('stdout.txt', 'w')





            share|improve this answer


























              11












              11








              11







              import sys
              sys.stdout = open('stdout.txt', 'w')





              share|improve this answer













              import sys
              sys.stdout = open('stdout.txt', 'w')






              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Jan 13 '11 at 0:52









              Cat Plus PlusCat Plus Plus

              93.3k23169203




              93.3k23169203























                  3














                  You need a terminal multiplexer like either tmux or GNU screen



                  I'm surprised that a small comment by Ryan Amos' to the original question is the only mention of a solution far preferable to all the others on offer, no matter how clever the python trickery may be and how many upvotes they've received. Further to Ryan's comment, tmux is a nice alternative to GNU screen.



                  But the principle is the same: if you ever find yourself wanting to leave a terminal job running while you log-out, head to the cafe for a sandwich, pop to the bathroom, go home (etc) and then later, reconnect to your terminal session from anywhere or any computer as though you'd never been away, terminal multiplexers are the answer. Think of them as VNC or remote desktop for terminal sessions. Anything else is a workaround. As a bonus, when the boss and/or partner comes in and you inadvertently ctrl-w / cmd-w your terminal window instead of your browser window with its dodgy content, you won't have lost the last 18 hours-worth of processing!






                  share|improve this answer





















                  • 2





                    while it is a good answer for the part of the question appeared after the edit; it does not answer the question in the title (most people come here from google for the title)

                    – jfs
                    Jul 15 '15 at 14:01











                  • That's a fair point, and one I hadn't considered.

                    – duncan
                    Jul 15 '15 at 17:57











                  • It looks like tmux has moved to tmux.github.io

                    – Teepeemm
                    Mar 3 '17 at 3:19
















                  3














                  You need a terminal multiplexer like either tmux or GNU screen



                  I'm surprised that a small comment by Ryan Amos' to the original question is the only mention of a solution far preferable to all the others on offer, no matter how clever the python trickery may be and how many upvotes they've received. Further to Ryan's comment, tmux is a nice alternative to GNU screen.



                  But the principle is the same: if you ever find yourself wanting to leave a terminal job running while you log-out, head to the cafe for a sandwich, pop to the bathroom, go home (etc) and then later, reconnect to your terminal session from anywhere or any computer as though you'd never been away, terminal multiplexers are the answer. Think of them as VNC or remote desktop for terminal sessions. Anything else is a workaround. As a bonus, when the boss and/or partner comes in and you inadvertently ctrl-w / cmd-w your terminal window instead of your browser window with its dodgy content, you won't have lost the last 18 hours-worth of processing!






                  share|improve this answer





















                  • 2





                    while it is a good answer for the part of the question appeared after the edit; it does not answer the question in the title (most people come here from google for the title)

                    – jfs
                    Jul 15 '15 at 14:01











                  • That's a fair point, and one I hadn't considered.

                    – duncan
                    Jul 15 '15 at 17:57











                  • It looks like tmux has moved to tmux.github.io

                    – Teepeemm
                    Mar 3 '17 at 3:19














                  3












                  3








                  3







                  You need a terminal multiplexer like either tmux or GNU screen



                  I'm surprised that a small comment by Ryan Amos' to the original question is the only mention of a solution far preferable to all the others on offer, no matter how clever the python trickery may be and how many upvotes they've received. Further to Ryan's comment, tmux is a nice alternative to GNU screen.



                  But the principle is the same: if you ever find yourself wanting to leave a terminal job running while you log-out, head to the cafe for a sandwich, pop to the bathroom, go home (etc) and then later, reconnect to your terminal session from anywhere or any computer as though you'd never been away, terminal multiplexers are the answer. Think of them as VNC or remote desktop for terminal sessions. Anything else is a workaround. As a bonus, when the boss and/or partner comes in and you inadvertently ctrl-w / cmd-w your terminal window instead of your browser window with its dodgy content, you won't have lost the last 18 hours-worth of processing!






                  share|improve this answer















                  You need a terminal multiplexer like either tmux or GNU screen



                  I'm surprised that a small comment by Ryan Amos' to the original question is the only mention of a solution far preferable to all the others on offer, no matter how clever the python trickery may be and how many upvotes they've received. Further to Ryan's comment, tmux is a nice alternative to GNU screen.



                  But the principle is the same: if you ever find yourself wanting to leave a terminal job running while you log-out, head to the cafe for a sandwich, pop to the bathroom, go home (etc) and then later, reconnect to your terminal session from anywhere or any computer as though you'd never been away, terminal multiplexers are the answer. Think of them as VNC or remote desktop for terminal sessions. Anything else is a workaround. As a bonus, when the boss and/or partner comes in and you inadvertently ctrl-w / cmd-w your terminal window instead of your browser window with its dodgy content, you won't have lost the last 18 hours-worth of processing!







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Aug 23 '17 at 5:17









                  jfs

                  273k825791136




                  273k825791136










                  answered May 17 '15 at 14:13









                  duncanduncan

                  1,27621019




                  1,27621019








                  • 2





                    while it is a good answer for the part of the question appeared after the edit; it does not answer the question in the title (most people come here from google for the title)

                    – jfs
                    Jul 15 '15 at 14:01











                  • That's a fair point, and one I hadn't considered.

                    – duncan
                    Jul 15 '15 at 17:57











                  • It looks like tmux has moved to tmux.github.io

                    – Teepeemm
                    Mar 3 '17 at 3:19














                  • 2





                    while it is a good answer for the part of the question appeared after the edit; it does not answer the question in the title (most people come here from google for the title)

                    – jfs
                    Jul 15 '15 at 14:01











                  • That's a fair point, and one I hadn't considered.

                    – duncan
                    Jul 15 '15 at 17:57











                  • It looks like tmux has moved to tmux.github.io

                    – Teepeemm
                    Mar 3 '17 at 3:19








                  2




                  2





                  while it is a good answer for the part of the question appeared after the edit; it does not answer the question in the title (most people come here from google for the title)

                  – jfs
                  Jul 15 '15 at 14:01





                  while it is a good answer for the part of the question appeared after the edit; it does not answer the question in the title (most people come here from google for the title)

                  – jfs
                  Jul 15 '15 at 14:01













                  That's a fair point, and one I hadn't considered.

                  – duncan
                  Jul 15 '15 at 17:57





                  That's a fair point, and one I hadn't considered.

                  – duncan
                  Jul 15 '15 at 17:57













                  It looks like tmux has moved to tmux.github.io

                  – Teepeemm
                  Mar 3 '17 at 3:19





                  It looks like tmux has moved to tmux.github.io

                  – Teepeemm
                  Mar 3 '17 at 3:19











                  2














                  Based on this answer: https://stackoverflow.com/a/5916874/1060344, here is another way I figured out which I use in one of my projects. For whatever you replace sys.stderr or sys.stdout with, you have to make sure that the replacement complies with file interface, especially if this is something you are doing because stderr/stdout are used in some other library that is not under your control. That library may be using other methods of file object.



                  Check out this way where I still let everything go do stderr/stdout (or any file for that matter) and also send the message to a log file using Python's logging facility (but you can really do anything with this):



                  class FileToLogInterface(file):
                  '''
                  Interface to make sure that everytime anything is written to stderr, it is
                  also forwarded to a file.
                  '''

                  def __init__(self, *args, **kwargs):
                  if 'cfg' not in kwargs:
                  raise TypeError('argument cfg is required.')
                  else:
                  if not isinstance(kwargs['cfg'], config.Config):
                  raise TypeError(
                  'argument cfg should be a valid '
                  'PostSegmentation configuration object i.e. '
                  'postsegmentation.config.Config')
                  self._cfg = kwargs['cfg']
                  kwargs.pop('cfg')

                  self._logger = logging.getlogger('access_log')

                  super(FileToLogInterface, self).__init__(*args, **kwargs)

                  def write(self, msg):
                  super(FileToLogInterface, self).write(msg)
                  self._logger.info(msg)





                  share|improve this answer






























                    2














                    Based on this answer: https://stackoverflow.com/a/5916874/1060344, here is another way I figured out which I use in one of my projects. For whatever you replace sys.stderr or sys.stdout with, you have to make sure that the replacement complies with file interface, especially if this is something you are doing because stderr/stdout are used in some other library that is not under your control. That library may be using other methods of file object.



                    Check out this way where I still let everything go do stderr/stdout (or any file for that matter) and also send the message to a log file using Python's logging facility (but you can really do anything with this):



                    class FileToLogInterface(file):
                    '''
                    Interface to make sure that everytime anything is written to stderr, it is
                    also forwarded to a file.
                    '''

                    def __init__(self, *args, **kwargs):
                    if 'cfg' not in kwargs:
                    raise TypeError('argument cfg is required.')
                    else:
                    if not isinstance(kwargs['cfg'], config.Config):
                    raise TypeError(
                    'argument cfg should be a valid '
                    'PostSegmentation configuration object i.e. '
                    'postsegmentation.config.Config')
                    self._cfg = kwargs['cfg']
                    kwargs.pop('cfg')

                    self._logger = logging.getlogger('access_log')

                    super(FileToLogInterface, self).__init__(*args, **kwargs)

                    def write(self, msg):
                    super(FileToLogInterface, self).write(msg)
                    self._logger.info(msg)





                    share|improve this answer




























                      2












                      2








                      2







                      Based on this answer: https://stackoverflow.com/a/5916874/1060344, here is another way I figured out which I use in one of my projects. For whatever you replace sys.stderr or sys.stdout with, you have to make sure that the replacement complies with file interface, especially if this is something you are doing because stderr/stdout are used in some other library that is not under your control. That library may be using other methods of file object.



                      Check out this way where I still let everything go do stderr/stdout (or any file for that matter) and also send the message to a log file using Python's logging facility (but you can really do anything with this):



                      class FileToLogInterface(file):
                      '''
                      Interface to make sure that everytime anything is written to stderr, it is
                      also forwarded to a file.
                      '''

                      def __init__(self, *args, **kwargs):
                      if 'cfg' not in kwargs:
                      raise TypeError('argument cfg is required.')
                      else:
                      if not isinstance(kwargs['cfg'], config.Config):
                      raise TypeError(
                      'argument cfg should be a valid '
                      'PostSegmentation configuration object i.e. '
                      'postsegmentation.config.Config')
                      self._cfg = kwargs['cfg']
                      kwargs.pop('cfg')

                      self._logger = logging.getlogger('access_log')

                      super(FileToLogInterface, self).__init__(*args, **kwargs)

                      def write(self, msg):
                      super(FileToLogInterface, self).write(msg)
                      self._logger.info(msg)





                      share|improve this answer















                      Based on this answer: https://stackoverflow.com/a/5916874/1060344, here is another way I figured out which I use in one of my projects. For whatever you replace sys.stderr or sys.stdout with, you have to make sure that the replacement complies with file interface, especially if this is something you are doing because stderr/stdout are used in some other library that is not under your control. That library may be using other methods of file object.



                      Check out this way where I still let everything go do stderr/stdout (or any file for that matter) and also send the message to a log file using Python's logging facility (but you can really do anything with this):



                      class FileToLogInterface(file):
                      '''
                      Interface to make sure that everytime anything is written to stderr, it is
                      also forwarded to a file.
                      '''

                      def __init__(self, *args, **kwargs):
                      if 'cfg' not in kwargs:
                      raise TypeError('argument cfg is required.')
                      else:
                      if not isinstance(kwargs['cfg'], config.Config):
                      raise TypeError(
                      'argument cfg should be a valid '
                      'PostSegmentation configuration object i.e. '
                      'postsegmentation.config.Config')
                      self._cfg = kwargs['cfg']
                      kwargs.pop('cfg')

                      self._logger = logging.getlogger('access_log')

                      super(FileToLogInterface, self).__init__(*args, **kwargs)

                      def write(self, msg):
                      super(FileToLogInterface, self).write(msg)
                      self._logger.info(msg)






                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited May 23 '17 at 11:33









                      Community

                      11




                      11










                      answered Jan 30 '15 at 12:48









                      vaidikvaidik

                      1,54011120




                      1,54011120























                          1














                          Programs written in other languages (e.g. C) have to do special magic (called double-forking) expressly to detach from the terminal (and to prevent zombie processes). So, I think the best solution is to emulate them.



                          A plus of re-executing your program is, you can choose redirections on the command-line, e.g. /usr/bin/python mycoolscript.py 2>&1 1>/dev/null



                          See this post for more info: What is the reason for performing a double fork when creating a daemon?






                          share|improve this answer


























                          • Eh... can't say I'm a fan of processes managing their own double-forking. It's so common an idiom, and so easy to code wrong if you aren't careful. Better to write your process to run in the foreground, and use a system background task manager (systemd, upstart) or other utility (daemon(1)) to handle the forking boilerplate.

                            – Lucretiel
                            Dec 2 '14 at 5:09
















                          1














                          Programs written in other languages (e.g. C) have to do special magic (called double-forking) expressly to detach from the terminal (and to prevent zombie processes). So, I think the best solution is to emulate them.



                          A plus of re-executing your program is, you can choose redirections on the command-line, e.g. /usr/bin/python mycoolscript.py 2>&1 1>/dev/null



                          See this post for more info: What is the reason for performing a double fork when creating a daemon?






                          share|improve this answer


























                          • Eh... can't say I'm a fan of processes managing their own double-forking. It's so common an idiom, and so easy to code wrong if you aren't careful. Better to write your process to run in the foreground, and use a system background task manager (systemd, upstart) or other utility (daemon(1)) to handle the forking boilerplate.

                            – Lucretiel
                            Dec 2 '14 at 5:09














                          1












                          1








                          1







                          Programs written in other languages (e.g. C) have to do special magic (called double-forking) expressly to detach from the terminal (and to prevent zombie processes). So, I think the best solution is to emulate them.



                          A plus of re-executing your program is, you can choose redirections on the command-line, e.g. /usr/bin/python mycoolscript.py 2>&1 1>/dev/null



                          See this post for more info: What is the reason for performing a double fork when creating a daemon?






                          share|improve this answer















                          Programs written in other languages (e.g. C) have to do special magic (called double-forking) expressly to detach from the terminal (and to prevent zombie processes). So, I think the best solution is to emulate them.



                          A plus of re-executing your program is, you can choose redirections on the command-line, e.g. /usr/bin/python mycoolscript.py 2>&1 1>/dev/null



                          See this post for more info: What is the reason for performing a double fork when creating a daemon?







                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited May 23 '17 at 12:10









                          Community

                          11




                          11










                          answered Jun 8 '13 at 17:23









                          jpaughjpaugh

                          3,96632569




                          3,96632569













                          • Eh... can't say I'm a fan of processes managing their own double-forking. It's so common an idiom, and so easy to code wrong if you aren't careful. Better to write your process to run in the foreground, and use a system background task manager (systemd, upstart) or other utility (daemon(1)) to handle the forking boilerplate.

                            – Lucretiel
                            Dec 2 '14 at 5:09



















                          • Eh... can't say I'm a fan of processes managing their own double-forking. It's so common an idiom, and so easy to code wrong if you aren't careful. Better to write your process to run in the foreground, and use a system background task manager (systemd, upstart) or other utility (daemon(1)) to handle the forking boilerplate.

                            – Lucretiel
                            Dec 2 '14 at 5:09

















                          Eh... can't say I'm a fan of processes managing their own double-forking. It's so common an idiom, and so easy to code wrong if you aren't careful. Better to write your process to run in the foreground, and use a system background task manager (systemd, upstart) or other utility (daemon(1)) to handle the forking boilerplate.

                          – Lucretiel
                          Dec 2 '14 at 5:09





                          Eh... can't say I'm a fan of processes managing their own double-forking. It's so common an idiom, and so easy to code wrong if you aren't careful. Better to write your process to run in the foreground, and use a system background task manager (systemd, upstart) or other utility (daemon(1)) to handle the forking boilerplate.

                          – Lucretiel
                          Dec 2 '14 at 5:09











                          0














                          @marcog



                          The second option is only good if script get excuted in a go .Or script should get executed completely only then the output goes into that file And infinite loops should`nt be present(optimally). Best solution if it is a simple script.






                          share|improve this answer






























                            0














                            @marcog



                            The second option is only good if script get excuted in a go .Or script should get executed completely only then the output goes into that file And infinite loops should`nt be present(optimally). Best solution if it is a simple script.






                            share|improve this answer




























                              0












                              0








                              0







                              @marcog



                              The second option is only good if script get excuted in a go .Or script should get executed completely only then the output goes into that file And infinite loops should`nt be present(optimally). Best solution if it is a simple script.






                              share|improve this answer















                              @marcog



                              The second option is only good if script get excuted in a go .Or script should get executed completely only then the output goes into that file And infinite loops should`nt be present(optimally). Best solution if it is a simple script.







                              share|improve this answer














                              share|improve this answer



                              share|improve this answer








                              edited Nov 25 '18 at 5:10

























                              answered Nov 25 '18 at 5:01









                              yunusyunus

                              67149




                              67149























                                  -1














                                  Here is a variation of Yuda Prawira answer:




                                  • implement flush() and all the file attributes

                                  • write it as a contextmanager

                                  • capture stderr also


                                  .



                                  import contextlib, sys

                                  @contextlib.contextmanager
                                  def log_print(file):
                                  # capture all outputs to a log file while still printing it
                                  class Logger:
                                  def __init__(self, file):
                                  self.terminal = sys.stdout
                                  self.log = file

                                  def write(self, message):
                                  self.terminal.write(message)
                                  self.log.write(message)

                                  def __getattr__(self, attr):
                                  return getattr(self.terminal, attr)

                                  logger = Logger(file)

                                  _stdout = sys.stdout
                                  _stderr = sys.stderr
                                  sys.stdout = logger
                                  sys.stderr = logger
                                  try:
                                  yield logger.log
                                  finally:
                                  sys.stdout = _stdout
                                  sys.stderr = _stderr


                                  with log_print(open('mylogfile.log', 'w')):
                                  print('hello world')
                                  print('hello world on stderr', file=sys.stderr)

                                  # you can capture the output to a string with:
                                  # with log_print(io.StringIO()) as log:
                                  # ....
                                  # print('[captured output]', log.getvalue())





                                  share|improve this answer






























                                    -1














                                    Here is a variation of Yuda Prawira answer:




                                    • implement flush() and all the file attributes

                                    • write it as a contextmanager

                                    • capture stderr also


                                    .



                                    import contextlib, sys

                                    @contextlib.contextmanager
                                    def log_print(file):
                                    # capture all outputs to a log file while still printing it
                                    class Logger:
                                    def __init__(self, file):
                                    self.terminal = sys.stdout
                                    self.log = file

                                    def write(self, message):
                                    self.terminal.write(message)
                                    self.log.write(message)

                                    def __getattr__(self, attr):
                                    return getattr(self.terminal, attr)

                                    logger = Logger(file)

                                    _stdout = sys.stdout
                                    _stderr = sys.stderr
                                    sys.stdout = logger
                                    sys.stderr = logger
                                    try:
                                    yield logger.log
                                    finally:
                                    sys.stdout = _stdout
                                    sys.stderr = _stderr


                                    with log_print(open('mylogfile.log', 'w')):
                                    print('hello world')
                                    print('hello world on stderr', file=sys.stderr)

                                    # you can capture the output to a string with:
                                    # with log_print(io.StringIO()) as log:
                                    # ....
                                    # print('[captured output]', log.getvalue())





                                    share|improve this answer




























                                      -1












                                      -1








                                      -1







                                      Here is a variation of Yuda Prawira answer:




                                      • implement flush() and all the file attributes

                                      • write it as a contextmanager

                                      • capture stderr also


                                      .



                                      import contextlib, sys

                                      @contextlib.contextmanager
                                      def log_print(file):
                                      # capture all outputs to a log file while still printing it
                                      class Logger:
                                      def __init__(self, file):
                                      self.terminal = sys.stdout
                                      self.log = file

                                      def write(self, message):
                                      self.terminal.write(message)
                                      self.log.write(message)

                                      def __getattr__(self, attr):
                                      return getattr(self.terminal, attr)

                                      logger = Logger(file)

                                      _stdout = sys.stdout
                                      _stderr = sys.stderr
                                      sys.stdout = logger
                                      sys.stderr = logger
                                      try:
                                      yield logger.log
                                      finally:
                                      sys.stdout = _stdout
                                      sys.stderr = _stderr


                                      with log_print(open('mylogfile.log', 'w')):
                                      print('hello world')
                                      print('hello world on stderr', file=sys.stderr)

                                      # you can capture the output to a string with:
                                      # with log_print(io.StringIO()) as log:
                                      # ....
                                      # print('[captured output]', log.getvalue())





                                      share|improve this answer















                                      Here is a variation of Yuda Prawira answer:




                                      • implement flush() and all the file attributes

                                      • write it as a contextmanager

                                      • capture stderr also


                                      .



                                      import contextlib, sys

                                      @contextlib.contextmanager
                                      def log_print(file):
                                      # capture all outputs to a log file while still printing it
                                      class Logger:
                                      def __init__(self, file):
                                      self.terminal = sys.stdout
                                      self.log = file

                                      def write(self, message):
                                      self.terminal.write(message)
                                      self.log.write(message)

                                      def __getattr__(self, attr):
                                      return getattr(self.terminal, attr)

                                      logger = Logger(file)

                                      _stdout = sys.stdout
                                      _stderr = sys.stderr
                                      sys.stdout = logger
                                      sys.stderr = logger
                                      try:
                                      yield logger.log
                                      finally:
                                      sys.stdout = _stdout
                                      sys.stderr = _stderr


                                      with log_print(open('mylogfile.log', 'w')):
                                      print('hello world')
                                      print('hello world on stderr', file=sys.stderr)

                                      # you can capture the output to a string with:
                                      # with log_print(io.StringIO()) as log:
                                      # ....
                                      # print('[captured output]', log.getvalue())






                                      share|improve this answer














                                      share|improve this answer



                                      share|improve this answer








                                      edited Sep 5 '18 at 13:41

























                                      answered Feb 19 '18 at 16:48









                                      damiodamio

                                      3,41522443




                                      3,41522443















                                          這個網誌中的熱門文章

                                          Academy of Television Arts & Sciences

                                          L'Équipe

                                          1995 France bombings