Python 3.4.3 subprocess.Popen get output of command without piping?

前端 未结 4 1925
无人及你
无人及你 2021-02-06 05:32

I am trying to assign the output of a command to a variable without the command thinking that it is being piped. The reason for this is that the command in question gives unform

相关标签:
4条回答
  • 2021-02-06 05:40

    Many programs automatically turn off colour printing codes when they detect they are not connected directly to a terminal. Many programs will have a flag so you can force colour output. You could add this flag to your process call. For example:

    grep "search term" inputfile.txt 
    # prints colour to the terminal in most OSes
    
    grep "search term" inputfile.txt | less
    # output goes to less rather than terminal, so colour is turned off 
    
    grep "search term" inputfile.txt --color | less
    # forces colour output even when not connected to terminal 
    

    Be warned though. The actual colour output is done by the terminal. The terminal interprets special character espace codes and changes the text colour and background color accordingly. Without the terminal to interpret the colour codes you will just see the text in black with these escape codes interspersed throughout.

    0 讨论(0)
  • 2021-02-06 05:45

    Yes, you can use the pty module.

    >>> import subprocess
    >>> p = subprocess.Popen(["ls", "--color=auto"], stdout=subprocess.PIPE)
    >>> p.communicate()[0]
    # Output does not appear in colour
    

    With pty:

    import subprocess
    import pty
    import os
    
    master, slave = pty.openpty()
    p = subprocess.Popen(["ls", "--color=auto"], stdout=slave)
    p.communicate()
    print(os.read(master, 100)) # Print 100 bytes
    # Prints with colour formatting info
    

    Note from the docs:

    Because pseudo-terminal handling is highly platform dependent, there is code to do it only for Linux. (The Linux code is supposed to work on other platforms, but hasn’t been tested yet.)

    A less than beautiful way of reading the whole output to the end in one go:

    def num_bytes_readable(fd):
        import array
        import fcntl
        import termios
        buf = array.array('i', [0])
        if fcntl.ioctl(fd, termios.FIONREAD, buf, 1) == -1:
            raise Exception("We really should have had data")
        return buf[0]
    
    print(os.read(master, num_bytes_readable(master)))
    

    Edit: nicer way of getting the content at once thanks to @Antti Haapala:

    os.close(slave)
    f = os.fdopen(master)
    print(f.read())
    

    Edit: people are right to point out that this will deadlock if the process generates a large output, so @Antti Haapala's answer is better.

    0 讨论(0)
  • 2021-02-06 05:55

    Using pexpect:

    2.py:

    import sys
    
    if sys.stdout.isatty():
        print('hello')
    else:
        print('goodbye')
    

    subprocess:

    import subprocess
    
    p = subprocess.Popen(
        ['python3.4', '2.py'],
        stdout=subprocess.PIPE
    )
    
    print(p.stdout.read())
    
    --output:--
    goodbye
    

    pexpect:

    import pexpect
    
    child = pexpect.spawn('python3.4 2.py')
    
    child.expect(pexpect.EOF)
    print(child.before)  #Print all the output before the expectation.
    
    --output:--
    hello
    

    Here it is with grep --colour=auto:

    import subprocess
    
    p = subprocess.Popen(
        ['grep', '--colour=auto', 'hello', 'data.txt'],
        stdout=subprocess.PIPE
    )
    
    print(p.stdout.read())
    
    import pexpect
    
    child = pexpect.spawn('grep --colour=auto hello data.txt')
    child.expect(pexpect.EOF)
    print(child.before)
    
    --output:--
    b'hello world\n'
    b'\x1b[01;31mhello\x1b[00m world\r\n'
    
    0 讨论(0)
  • 2021-02-06 06:04

    A working polyglot example (works the same for Python 2 and Python 3), using pty.

    import subprocess
    import pty
    import os
    import sys
    
    master, slave = pty.openpty()
    # direct stderr also to the pty!
    process = subprocess.Popen(
        ['ls', '-al', '--color=auto'],
        stdout=slave,
        stderr=subprocess.STDOUT
    )
    
    # close the slave descriptor! otherwise we will
    # hang forever waiting for input
    os.close(slave)
    
    def reader(fd):
        try:
            while True:
                buffer = os.read(fd, 1024)
                if not buffer:
                    return
    
                yield buffer
    
        # Unfortunately with a pty, an 
        # IOError will be thrown at EOF
        # On Python 2, OSError will be thrown instead.
        except (IOError, OSError) as e:
            pass
    
    # read chunks (yields bytes)
    for i in reader(master):
        # and write them to stdout file descriptor
        os.write(1, b'<chunk>' + i + b'</chunk>')
    
    0 讨论(0)
提交回复
热议问题