我正在尝试将命令的输出分配给变量,而不会让命令认为它正在被管道传输。这样做的原因是,如果正在通过管道传输,有问题的命令会将未格式化的文本作为输出,但如果从终端运行,则会给出颜色格式化的文本。我需要获得这种颜色格式的文本。
到目前为止,我已经尝试了一些事情。我这样试过Popen:
output = subprocess.Popen(command, stdout=subprocess.PIPE)
output = output.communicate()[0]
output = output.decode()
print(output)
这将让我打印输出,但它给了我输出命令时得到的无格式输出。这是有道理的,因为我在Python代码中将它管道化。但我很好奇是否有办法将此命令的输出直接分配给变量,而没有运行管道版本的命令。
我还尝试了以下依赖于check_output的版本:
output = subprocess.check_output(command)
output = output.decode()
print(output)
我再次获得与命令管道时命令返回的相同的无格式输出。
有没有办法获取格式化的输出,这个命令通常会从终端提供的输出,当它没有被管道传输时?
答案 0 :(得分:9)
使用pexpect:
2.py:
import sys
if sys.stdout.isatty():
print('hello')
else:
print('goodbye')
子:
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
这是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'
答案 1 :(得分:4)
是的,您可以使用pty module。
>>> import subprocess
>>> p = subprocess.Popen(["ls", "--color=auto"], stdout=subprocess.PIPE)
>>> p.communicate()[0]
# Output does not appear in colour
使用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
来自文档的说明:
因为伪终端处理高度依赖平台,所以 是只为Linux做的代码。 (Linux代码应该可行 在其他平台上,但尚未经过测试。)
一次性读取整个输出的不太美妙的方式:
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)))
编辑:感谢@Antti Haapala获得内容的更好方式:
os.close(slave)
f = os.fdopen(master)
print(f.read())
编辑:人们指出如果流程产生大量输出会导致死锁,所以@Antti Haapala的答案更好。
答案 2 :(得分:3)
使用pty
的工作多语言示例(对于Python 2和Python 3也是如此)。
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>')
答案 3 :(得分:1)
许多程序在检测到它们未直接连接到终端时会自动关闭彩色打印代码。许多程序都会有一个标志,因此您可以强制输出颜色。您可以将此标志添加到您的流程调用中。例如:
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
但请注意。实际的颜色输出由终端完成。终端解释特殊字符espace代码并相应地更改文本颜色和背景颜色。如果没有终端解释颜色代码,您将看到黑色文本,这些逃逸代码贯穿始终。