Search code examples
pythonlinuxbashdialogwhiptail

Feed python output to whiptail


I would like to use a TUI (text user interface) on a headless linux server by passing output of some PYTHON code to 'whiptail'. Unfortunately, nothing seems to happen in whiptail. When I pipe the output from a regular shell script, then whiptail works fine. Here is what I have:

data-gen.sh

#!/bin/bash
echo 10
sleep 1
echo 20
sleep 1
...
...
echo 100
sleep 1

$ ./data-gen.sh | whiptail --title "TEST" --gauge "GAUGE" 0 50 0

I get the below progress bar incrementing as expected.

Whiptail working when piping output from shell script


Now I try to replicate same thing from python:

data-gen.py

#!/usr/bin/python
import time

print 10
time.sleep(1)
...
...
print 100
time.sleep(1)

$ ./data-gen.py | whiptail --title "TEST" --gauge "GAUGE" 0 50 0

I get the below progress bar staying at 0%. No increment seen. Whiptail does exit once the python program in the background has exited.

No change in progress bar when piping python output

Any ideas how to get python output to be piped successfully to whiptail ? I have not tried this with dialog; since I wanted to stick to whiptail which is pre-installed on most ubuntu distros.


Solution

  • man whiptail says:

    --gauge text height width percent

              A gauge box displays a meter along the bottom of the
              box.  The meter indicates a percentage.  New percentages
              are read from standard input, one integer per line.  The
              meter is updated to reflect each new percentage.  If
              stdin is XXX, the first following line is a percentage
              and subsequent lines up to another XXX are used for a
              new prompt.  The gauge exits when EOF is reached on
              stdin.
    

    That means that whiptail reads from standard input. Many programs commonly buffer output when it's not going to the file. To force python to produce unbuffered output you can either:

    • Run it with unbuffer:

      $ unbuffer ./data-gen.py | whiptail --title "TEST" --gauge "GAUGE" 0 50 0
      
    • Use -u switch on the command line:

      $ python -u ./data-gen.py | whiptail --title "TEST" --gauge "GAUGE" 0 50 0
      
    • Modify the shebang of data-gen.py:

      #!/usr/bin/python -u
      import time
      print 10
      time.sleep(1)
      print 20
      time.sleep(1)
      print 100
      time.sleep(1)
      
    • Manually flush stdout after each print:

      #!/usr/bin/python
      import time
      import sys
      
      print 10
      sys.stdout.flush()
      time.sleep(1)
      print 20
      sys.stdout.flush()
      time.sleep(1)
      print 100
      sys.stdout.flush()
      time.sleep(1)
      
    • Set PYTHONUNBUFFERED environment variable:

      $ PYTHONUNBUFFERED=1 ./data-gen.py | whiptail --title "TEST" --gauge "GAUGE" 0 50 0