0

I have a python prog that I want to behave like a linux cmd when output is produced. The prog uses 'print()' and when run on the cmd line the printed stuff is clearly visible on the terminal. When I launch the prog with bash output redirect into a file the file stays empty. What's the mistake I'm making?

The printing part of the prog:

chktime = 0
chkper  = 10

while True:
    if time.time() - chktime > chkper:
        chktime = time.time() 
        diskusepct = get_asus_diskusepct()
        print('Asus tmpfs free: ' + diskusepct)
        if float(diskusepct) > 95.0:
            with open("asus_syslog.log", 'w') as sl:
                sl.write(get_asus_syslog())
    else:
        print('Wait')
        time.sleep(1)

From cmd line (as expected):

rpi4b:~/python $ ./asus_diskwatch_v1.0.py 
Asus tmpfs free: 1
Wait
Wait
Wait
Wait

With redirect (unexpected):

~/python $ ./asus_diskwatch_v1.0.py > asus_diskwatch.log &
[2] 4415
~/python $ cat asus_diskwatch.log
<nothing>

Feedback is appreciated.

Anwarvic
  • 12,156
  • 4
  • 49
  • 69
Gert Gottschalk
  • 1,658
  • 3
  • 25
  • 37

2 Answers2

1

What is happening here is output buffering. When print output is directed to a file, data is collected a certain amount until it is actually written to the file. If you waited long enough, you would notice the file suddenly has a large number of "Wait" lines. (If you want to test this, make the output some hundreds of characters in length, so you don't have to wait so long). See this question about ways to control the buffering: Disable output buffering

ErkkiRuohtula
  • 133
  • 1
  • 4
0

To solve your issue, I believe you need to do two things:

  • You need to change the writing mode from write 'w' to append'a' as writing mode overwrites earlier lines while append mode will append new lines.

  • You need to set the buffer size to 1 as the default buffer size is 8192.

So, your code should look like this:

chktime = 0
chkper  = 10

while True:
    if time.time() - chktime > chkper:
        chktime = time.time() 
        diskusepct = get_asus_diskusepct()
        print('Asus tmpfs free: ' + diskusepct)
        if float(diskusepct) > 95.0:
            with open("asus_syslog.log", 'a', buffering=1) as sl: # <-- changes here
                sl.write(get_asus_syslog())
    else:
        print('Wait')

Hope this solves your issue!

Anwarvic
  • 12,156
  • 4
  • 49
  • 69
  • (Deleted my bad comment about the appending flag - did not look attyour answer closely enough) – ErkkiRuohtula Oct 28 '19 at 06:54
  • As you can see, every time the `if` condition comes true, it creates a file in **write mode** which overrides previous content. Making the file creation outside the `while` loop should solve the problem, but the **append mode** should solve the problem as well. – Anwarvic Oct 28 '19 at 06:57
  • @ErkkiRuohtula, you didn't have to, it's totally OK :) – Anwarvic Oct 28 '19 at 06:58
  • 1
    Sure, I noticed I was commenting the wrong thing, the append flag is necessary for the log file written separately. – ErkkiRuohtula Oct 28 '19 at 06:58
  • The purpose of the if condition is actually to capture the syslog file from my router and store it once. There should be some break or exit cmd there, actually. There is a memory leak somewhere in the router and once the internal flash fills up it crashes. Asus so far couldn't help. So my idea is to write this script to watch if the flash gets close to 100% full, then get the syslog to see what was done last (to complain to Asus about), and then probably send me a warning email, or reboot the router automatically. Not sure if a rm -rf /tmp on the live router is a good idea. – Gert Gottschalk Oct 29 '19 at 05:20
  • Adding lines `sys.stdout.flush()` following the print lines fixed the re-direct issue. – Gert Gottschalk Oct 29 '19 at 05:22