How to preserve original color coding of output on the shell while doing a subprocess.Popen?

Question:

I have a simple Python script which live-prints the output of a command. Following is the script:

#!/usr/bin/env python3
import subprocess

def RunSubProcess(process, process_args):
    process = subprocess.Popen([process, process_args], 
                               stdout=subprocess.PIPE, 
                               stderr=subprocess.PIPE, 
                               universal_newlines=True)
    while process.stdout.readable():
        line = process.stdout.readline()
        if not line:
            break
        print(line.strip())

RunSubProcess('ls', '-la')

The script works well for what it should do but it loses color coding of the output on my shell. If I type ls -la, I get the output well-colored. But if I run the above Python script, it gives the output uncolored.

Is there an argument to subprocess.Popen that could preserve color coding of the shell it’s running on?

PS:
I am running this Python script on a bash shell on MacOS with Python 3.9.0 installed.

Asked By: TheWaterProgrammer

||

Answers:

Many programs detect whether they are connecterd to a terminal, and switch to different behaviors for interactive use.

Some provide options to force interactive features (try ls --color=always but what exactly works depends on your platform; this is not standardized behavior. The macOS ls man page says to set CLICOLOR=yes in the environment) and others can be fooled into believing they are running interactively by using the pty library, or pexpect which is a higher-level package and somewhat easier to work with.

Answered By: tripleee

This works and maintains color for me.

               cmd = "/bin/ls -l --color"

               # Run command. Print output in real-time. Maintain text colors.                                                                                
                proc = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE)                                                                              
                for line in iter(proc.stdout.readline, ""):                                                                                                    
                    line = line.decode("utf-8")                                                                                                                
                    if line == "":                                                                                                                             
                        break                                                                                                                                  
                    print(line.rstrip())                                                                                                                       
                rc = proc.poll()                                                                                                                               
                while rc is None:                                                                                                                              
                    time.sleep(0.1)                                                                                                                            
                    rc = proc.poll()             
Answered By: Myles Prather
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.