Lưu trữ đầu ra của lệnh con.Popen trong một chuỗi


300

Tôi đang cố gắng thực hiện một cuộc gọi hệ thống trong Python và lưu trữ đầu ra thành một chuỗi mà tôi có thể thao tác trong chương trình Python.

#!/usr/bin/python
import subprocess
p2 = subprocess.Popen("ntpq -p")

Tôi đã thử một vài điều bao gồm một số gợi ý ở đây:

Lấy ra đầu ra của sub process.call ()

nhưng không có may mắn


3
Thật tốt khi luôn đăng mã thực tế bạn đã chạy và truy nguyên thực tế hoặc bahaviour bất ngờ cho các câu hỏi cụ thể như thế này. Ví dụ, tôi không biết bạn đã cố gắng làm gì để có được đầu ra và tôi nghi ngờ bạn không thực sự đi xa đến mức đó với bạn, bạn sẽ gặp lỗi khi không tìm thấy tệp "ntpq -p", đây là một phần khác của vấn đề hơn bạn đang hỏi về.
Mike Graham

Câu trả lời:


467

Trong Python 2.7 hoặc Python 3

Thay vì tạo một Popenđối tượng trực tiếp, bạn có thể sử dụng subprocess.check_output()hàm để lưu trữ đầu ra của lệnh trong một chuỗi:

from subprocess import check_output
out = check_output(["ntpq", "-p"])

Trong Python 2.4-2.6

Sử dụng communicatephương pháp.

import subprocess
p = subprocess.Popen(["ntpq", "-p"], stdout=subprocess.PIPE)
out, err = p.communicate()

out là những gì bạn muốn.

Lưu ý quan trọng về các câu trả lời khác

Lưu ý cách tôi chuyển trong lệnh. Các "ntpq -p"ví dụ sẽ trả về một vấn đề khác. Vì Popenkhông gọi shell, nên bạn sẽ sử dụng danh sách lệnh và tùy chọn ["ntpq", "-p"].


3
Trong trường hợp này, python có chờ cuộc gọi hệ thống này kết thúc không? Hoặc là cần thiết để gọi rõ ràng chức năng Wait / Waitpid?
Không có loại

7
@NoneType, Popen.communicatekhông trả về cho đến khi quá trình kết thúc.
Mike Graham

10
nếu bạn muốn nhận luồng lỗi, hãy thêm stderr:p = subprocess.Popen(["ntpq", "-p"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Timofey

82
Cẩn thận, subprocess.check_output()trả về một bytesđối tượng, không phải a str. Nếu tất cả những gì bạn muốn làm là in kết quả, điều đó sẽ không tạo ra bất kỳ sự khác biệt nào. Nhưng nếu bạn muốn sử dụng một phương thức như myString.split("\n")kết quả, trước tiên bạn sẽ phải giải mã bytesđối tượng: subprocess.check_output(myParams).decode("utf-8")ví dụ.
TanguyP

17
việc thêm universal_newlines=Truelàm tham số đã giúp tôi trong Python 3 để lấy đối tượng chuỗi. Nếu Universal_newlines là True, chúng được mở ở chế độ văn bản với mã hóa mặc định. Mặt khác, chúng được mở dưới dạng luồng nhị phân.
Jonathan Komar

38

Điều này làm việc cho tôi để chuyển hướng thiết bị xuất chuẩn (stderr có thể được xử lý tương tự):

from subprocess import Popen, PIPE
pipe = Popen(path, stdout=PIPE)
text = pipe.communicate()[0]

Nếu nó không hiệu quả với bạn, vui lòng chỉ định chính xác vấn đề bạn gặp phải.


3
Điều này không tạo ra một số đối tượng kỳ lạ. Khi tôi chuyển đổi nó thành chuỗi, nó thoát khỏi khoảng trắng như thế nào \n.
Tomáš Zato - Tái lập lại

1
Lưu ý rằng điều này không kiểm tra nếu quy trình con chạy đúng. Bạn có thể muốn kiểm tra rằng pipe.returncode == 0sau dòng cuối cùng quá.
thakis

Lý do điều này hoạt động là vì Popentrả về một tuple stdoutstderrvì vậy khi bạn truy cập, [0]bạn chỉ cần lấy stdout. Bạn cũng có thể làm text, err = pipe.communicate()và sau đó textsẽ có những gì bạn mong đợi
Jona


22

sub process.Popen: http://docs.python.org/2/l Library / sub process.html # sub process.Popen

import subprocess

command = "ntpq -p"  # the shell command
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None, shell=True)

#Launch the shell command:
output = process.communicate()

print output[0]

Trong hàm tạo Popen, nếu shellTrue , bạn nên truyền lệnh dưới dạng chuỗi chứ không phải là chuỗi. Nếu không, chỉ cần chia lệnh thành một danh sách:

command = ["ntpq", "-p"]  # the shell command
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None)

Nếu bạn cũng cần đọc lỗi tiêu chuẩn, vào phần khởi tạo Popen, bạn có thể đặt stderr thành sub process.PIPE hoặc thành sub process.STDOUT :

import subprocess

command = "ntpq -p"  # the shell command
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)

#Launch the shell command:
output, error = process.communicate()

tuyệt vời đây là những gì tôi đang tìm kiếm
kRazzy R

14

cho Python 2.7+ câu trả lời thành ngữ là sử dụng subprocess.check_output()

Bạn cũng nên lưu ý việc xử lý các đối số khi gọi một quy trình con, vì nó có thể hơi khó hiểu ....

Nếu args chỉ là một lệnh đơn lẻ không có đối số của riêng nó (hoặc bạn đã shell=Trueđặt), thì đó có thể là một chuỗi. Nếu không thì nó phải là một danh sách.

ví dụ ... để gọi lslệnh, điều này là tốt:

from subprocess import check_call
check_call('ls')

đây là

from subprocess import check_call
check_call(['ls',])

tuy nhiên, nếu bạn muốn chuyển một số đối số cho lệnh shell, bạn không thể thực hiện điều này:

from subprocess import check_call
check_call('ls -al')

thay vào đó, bạn phải vượt qua nó như một danh sách:

from subprocess import check_call
check_call(['ls', '-al'])

các shlex.split()chức năng đôi khi có thể hữu ích để tách một chuỗi thành vỏ giống như cú pháp trước khi tạo một trình con ... như thế này:

from subprocess import check_call
import shlex
check_call(shlex.split('ls -al'))

Năm năm sau, câu hỏi này vẫn nhận được nhiều tình yêu. Cảm ơn bản cập nhật 2.7+, Corey!
Đánh dấu

11

Điều này hoạt động hoàn hảo cho tôi:

import subprocess
try:
    #prints results and merges stdout and std
    result = subprocess.check_output("echo %USERNAME%", stderr=subprocess.STDOUT, shell=True)
    print result
    #causes error and merges stdout and stderr
    result = subprocess.check_output("copy testfds", stderr=subprocess.STDOUT, shell=True)
except subprocess.CalledProcessError, ex: # error code <> 0 
    print "--------error------"
    print ex.cmd
    print ex.message
    print ex.returncode
    print ex.output # contains stdout and stderr together 

9

Điều này là hoàn hảo cho tôi. Bạn sẽ nhận được mã trả về, thiết bị xuất chuẩn và thiết bị xuất chuẩn trong một tuple.

from subprocess import Popen, PIPE

def console(cmd):
    p = Popen(cmd, shell=True, stdout=PIPE)
    out, err = p.communicate()
    return (p.returncode, out, err)

Ví dụ:

result = console('ls -l')
print 'returncode: %s' % result[0]
print 'output: %s' % result[1]
print 'error: %s' % result[2]

6

Câu trả lời được chấp nhận vẫn còn tốt, chỉ cần một vài nhận xét về các tính năng mới hơn. Kể từ python 3.6, bạn có thể xử lý mã hóa trực tiếp trong check_output, xem tài liệu . Điều này trả về một đối tượng chuỗi bây giờ:

import subprocess 
out = subprocess.check_output(["ls", "-l"], encoding="utf-8")

Trong python 3.7, một tham số capture_outputđã được thêm vào sub process.run (), một số xử lý Popen / PIPE cho chúng ta, xem tài liệu python :

import subprocess 
p2 = subprocess.run(["ls", "-l"], capture_output=True, encoding="utf-8")
p2.stdout

4
 import os   
 list = os.popen('pwd').read()

Trong trường hợp này, bạn sẽ chỉ có một yếu tố trong danh sách.


7
os.popenkhông được ủng hộ của các subprocessmô-đun.
Mike Graham

3
Điều này khá hữu ích cho quản trị viên trên một hộp cũ bằng cách sử dụng loạt Python 2.2.X.
Neil McF

4

Tôi đã viết một chức năng nhỏ dựa trên các câu trả lời khác ở đây:

def pexec(*args):
    return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0].rstrip()

Sử dụng:

changeset = pexec('hg','id','--id')
branch = pexec('hg','id','--branch')
revnum = pexec('hg','id','--num')
print('%s : %s (%s)' % (revnum, changeset, branch))

4

Trong Python 3.7, một đối số từ khóa mới capture_outputđã được giới thiệu cho subprocess.run. Kích hoạt ngắn và đơn giản:

import subprocess

p = subprocess.run("echo 'hello world!'", capture_output=True, shell=True, encoding="utf8")
assert p.stdout == 'hello world!\n'

1
import subprocess
output = str(subprocess.Popen("ntpq -p",shell = True,stdout = subprocess.PIPE, 
stderr = subprocess.STDOUT).communicate()[0])

Đây là một giải pháp dòng


0

Sau đây ghi lại stdout và stderr của quá trình trong một biến duy nhất. Nó tương thích với Python 2 và 3:

from subprocess import check_output, CalledProcessError, STDOUT

command = ["ls", "-l"]
try:
    output = check_output(command, stderr=STDOUT).decode()
    success = True 
except CalledProcessError as e:
    output = e.output.decode()
    success = False

Nếu lệnh của bạn là một chuỗi chứ không phải là một mảng, hãy đặt tiền tố này bằng:

import shlex
command = shlex.split(command)

0

Đối với python 3.5 tôi đưa ra chức năng dựa trên câu trả lời trước đó. Nhật ký có thể bị xóa, nghĩ rằng thật tốt khi có

import shlex
from subprocess import check_output, CalledProcessError, STDOUT


def cmdline(command):
    log("cmdline:{}".format(command))
    cmdArr = shlex.split(command)
    try:
        output = check_output(cmdArr,  stderr=STDOUT).decode()
        log("Success:{}".format(output))
    except (CalledProcessError) as e:
        output = e.output.decode()
        log("Fail:{}".format(output))
    except (Exception) as e:
        output = str(e);
        log("Fail:{}".format(e))
    return str(output)


def log(msg):
    msg = str(msg)
    d_date = datetime.datetime.now()
    now = str(d_date.strftime("%Y-%m-%d %H:%M:%S"))
    print(now + " " + msg)
    if ("LOG_FILE" in globals()):
        with open(LOG_FILE, "a") as myfile:
            myfile.write(now + " " + msg + "\n")

0

Sử dụng ckeck_outputphương phápsubprocess

import subprocess
address = 192.168.x.x
res = subprocess.check_output(['ping', address, '-c', '3'])

Cuối cùng phân tích chuỗi

for line in res.splitlines():

Hy vọng nó sẽ giúp, mã hóa hạnh phúc

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.