Tee does not show output or write to file

11,231

Here's a simpler way of reproducing your issue:

$ cat foo.py
from time import sleep
while True: 
  sleep(2)
  print "hello"

$ python foo.py
hello
hello    
(...)

$ python foo.py | tee log
(no output)

This happens because python buffers stdout when it's not a terminal. The easiest way to unbuffer it is to use python -u:

$ python -u foo.py | tee log
hello
hello
(...)

You can also set the shebang to #!/usr/bin/python -u (this does not work with env).

Share:
11,231

Related videos on Youtube

Lily Mara
Author by

Lily Mara

Updated on September 16, 2022

Comments

  • Lily Mara
    Lily Mara over 1 year

    I wrote a python script to monitor the statuses of some network resources, an infinite pinger if you will. It pings the same 3 nodes forever until it receives a keyboard interrupt. I tried using tee to redirect the output of the program to a file, but it does not work:

    λ sudo ./pingster.py
    
    15:43:33        node1 SUCESS | node2 SUCESS | node3 SUCESS
    15:43:35        node1 SUCESS | node2 SUCESS | node3 SUCESS
    15:43:36        node1 SUCESS | node2 SUCESS | node3 SUCESS
    15:43:37        node1 SUCESS | node2 SUCESS | node3 SUCESS
    15:43:38        node1 SUCESS | node2 SUCESS | node3 SUCESS
    ^CTraceback (most recent call last):
      File "./pingster.py", line 42, in <module>
        main()
      File "./pingster.py", line 39, in main
        sleep(1)
    KeyboardInterrupt
    
    λ sudo ./pingster.py | tee ping.log
    # wait a few seconds
    ^CTraceback (most recent call last):
      File "./pingster.py", line 42, in <module>
        main()
      File "./pingster.py", line 39, in main
        sleep(1)
    KeyboardInterrupt
    
    λ file ping.log
    ping.log: empty 
    

    I am using colorama for my output, I thought that perhaps could be causing the issue, but I tried printing something before I even imported colorama, and the file is still empty. What am I doing wrong here?

    Edit: Here is the python file I'm using

    #!/home/nate/py-env/ping/bin/python
    
    from __future__ import print_function
    from datetime import datetime
    from collections import OrderedDict
    from time import sleep
    
    import ping
    import colorama
    
    
    def main():
        d = {
            'node1': '10.0.0.51',
            'node2': '10.0.0.50',
            'node3': '10.0.0.52',
        }
        addresses = OrderedDict(sorted(d.items(), key=lambda t: t[0]))
    
        colorama.init()
        while True:
            status = []
            time = datetime.now().time().strftime('%H:%M:%S')
            print(time, end='\t')
            for location, ip_address in addresses.items():
                loss, max_time, avg_time = ping.quiet_ping(ip_address, timeout=0.5)
                if loss < 50:
                    status.append('{0} SUCESS'.format(location))
                else:
                    status.append(
                        '{}{} FAIL{}'.format(
                            colorama.Fore.RED,
                            location,
                            colorama.Fore.RESET,
                        )
                    )
            print(' | '.join(status))
            sleep(1)
    
    if __name__ == '__main__':
        main()
    
  • Ar5hv1r
    Ar5hv1r almost 8 years
    If you can't modify the python invocation you can set the PYTHONUNBUFFERED environment variable to a non-empty string and this will have the same effect. man python describes the behavior in more detail