Hướng dẫn python run shell command and stream output - python chạy lệnh shell và đầu ra luồng

Tóm tắt điều hành (hoặc phiên bản "TL; DR"): Thật dễ dàng khi có nhiều nhất một subprocess.PIPE, nếu không thì nó khó.

Có thể là thời gian để giải thích một chút về cách subprocess.Popen làm điều của nó.

.

Hàm Popen cần phải đối phó với các luồng I/O từ 0 đến ba, hơi đồng thời. Chúng được ký hiệu là stdin,

for line in proc.stdout:
0 và
for line in proc.stdout:
1 như bình thường.

Bạn có thể cung cấp:

  • for line in proc.stdout:
    
    2, chỉ ra rằng bạn không muốn chuyển hướng luồng. Nó sẽ kế thừa những thứ này như bình thường. Lưu ý rằng trên các hệ thống POSIX, ít nhất, điều này không có nghĩa là nó sẽ sử dụng
    for line in proc.stdout:
    
    3 của Python, chỉ là stdout thực tế của Python; Xem bản demo ở cuối.
  • Giá trị
    for line in proc.stdout:
    
    4. Đây là một mô tả tệp "thô" (ít nhất là trong POSIX). .
  • Một luồng thực sự, bất kỳ đối tượng nào có phương thức
    for line in proc.stdout:
    
    8. Popen sẽ tìm thấy bộ mô tả cho luồng đó, sử dụng
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    
    0, và sau đó tiến hành như giá trị
    for line in proc.stdout:
    
    4.
  • subprocess.PIPE, chỉ ra rằng Python nên tạo ra một đường ống.
  • proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    
    3 (chỉ dành cho
    for line in proc.stdout:
    
    1): Nói với Python sử dụng cùng một mô tả như đối với
    for line in proc.stdout:
    
    0. Điều này chỉ có ý nghĩa nếu bạn cung cấp giá trị (không phải -____ 12) cho
    for line in proc.stdout:
    
    0, và thậm chí sau đó, nó chỉ cần nếu bạn đặt
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    
    8. (Nếu không, bạn chỉ có thể cung cấp cùng một đối số mà bạn đã cung cấp cho ____10, ví dụ:
    def communicate(self, input=None):
        ...
        # Optimization: If we are only using one pipe, or no pipe at
        # all, using select() or threads is unnecessary.
        if [self.stdin, self.stdout, self.stderr].count(None) >= 2:
    
    0.)

Các trường hợp dễ nhất (không có đường ống)

Nếu bạn chuyển hướng không có gì (để lại cả ba là giá trị

for line in proc.stdout:
2 mặc định hoặc cung cấp rõ ràng
for line in proc.stdout:
2),
def communicate(self, input=None):
    ...
    # Optimization: If we are only using one pipe, or no pipe at
    # all, using select() or threads is unnecessary.
    if [self.stdin, self.stdout, self.stderr].count(None) >= 2:
3 sẽ khá dễ dàng. Nó chỉ cần quay ra khỏi quy trình con và để nó chạy. Hoặc, nếu bạn chuyển hướng đến một người không phải là -____ 15, một
for line in proc.stdout:
4 hoặc một luồng ____ ____ 36, nó vẫn dễ dàng, vì hệ điều hành thực hiện tất cả các công việc. Python chỉ cần xoay chuyển quy trình con, kết nối stdin, stdout và/hoặc stderr của nó với các mô tả tệp được cung cấp.

Trường hợp vẫn còn dễ dàng: một ống

Nếu bạn chỉ chuyển đổi một luồng,

def communicate(self, input=None):
    ...
    # Optimization: If we are only using one pipe, or no pipe at
    # all, using select() or threads is unnecessary.
    if [self.stdin, self.stdout, self.stderr].count(None) >= 2:
3 vẫn có những thứ khá dễ dàng. Hãy chọn một luồng một lúc và xem.

Giả sử bạn muốn cung cấp một số stdin, nhưng hãy để ____10 và

for line in proc.stdout:
1 không được kiểm tra hoặc đi đến một bộ mô tả tập tin. Khi quá trình cha mẹ, chương trình Python của bạn chỉ cần sử dụng
from cStringIO import StringIO
import os
import subprocess
import sys

def show1():
   print 'start show1'
   save = sys.stdout
   sys.stdout = StringIO()
   print 'sys.stdout being buffered'
   proc = subprocess.Popen(['echo', 'hello'])
   proc.wait()
   in_stdout = sys.stdout.getvalue()
   sys.stdout = save
   print 'in buffer:', in_stdout

def show2():
   print 'start show2'
   save = sys.stdout
   sys.stdout = open(os.devnull, 'w')
   print 'after redirect sys.stdout'
   proc = subprocess.Popen(['echo', 'hello'])
   proc.wait()
   sys.stdout = save

show1()
show2()
1 để gửi dữ liệu xuống đường ống. Bạn có thể tự làm điều này, ví dụ:

proc = subprocess.Popen(cmd, stdin=subprocess.PIPE)
proc.stdin.write('here, have some data\n') # etc

Hoặc bạn có thể chuyển dữ liệu STDIN đến

from cStringIO import StringIO
import os
import subprocess
import sys

def show1():
   print 'start show1'
   save = sys.stdout
   sys.stdout = StringIO()
   print 'sys.stdout being buffered'
   proc = subprocess.Popen(['echo', 'hello'])
   proc.wait()
   in_stdout = sys.stdout.getvalue()
   sys.stdout = save
   print 'in buffer:', in_stdout

def show2():
   print 'start show2'
   save = sys.stdout
   sys.stdout = open(os.devnull, 'w')
   print 'after redirect sys.stdout'
   proc = subprocess.Popen(['echo', 'hello'])
   proc.wait()
   sys.stdout = save

show1()
show2()
2, sau đó
from cStringIO import StringIO
import os
import subprocess
import sys

def show1():
   print 'start show1'
   save = sys.stdout
   sys.stdout = StringIO()
   print 'sys.stdout being buffered'
   proc = subprocess.Popen(['echo', 'hello'])
   proc.wait()
   in_stdout = sys.stdout.getvalue()
   sys.stdout = save
   print 'in buffer:', in_stdout

def show2():
   print 'start show2'
   save = sys.stdout
   sys.stdout = open(os.devnull, 'w')
   print 'after redirect sys.stdout'
   proc = subprocess.Popen(['echo', 'hello'])
   proc.wait()
   sys.stdout = save

show1()
show2()
3 hiển thị ở trên. Không có đầu ra nào trở lại nên
from cStringIO import StringIO
import os
import subprocess
import sys

def show1():
   print 'start show1'
   save = sys.stdout
   sys.stdout = StringIO()
   print 'sys.stdout being buffered'
   proc = subprocess.Popen(['echo', 'hello'])
   proc.wait()
   in_stdout = sys.stdout.getvalue()
   sys.stdout = save
   print 'in buffer:', in_stdout

def show2():
   print 'start show2'
   save = sys.stdout
   sys.stdout = open(os.devnull, 'w')
   print 'after redirect sys.stdout'
   proc = subprocess.Popen(['echo', 'hello'])
   proc.wait()
   sys.stdout = save

show1()
show2()
4 chỉ có một công việc thực sự khác: nó cũng đóng đường ống cho bạn. .

Giả sử bạn muốn chụp

for line in proc.stdout:
0 nhưng chỉ để stdin
for line in proc.stdout:
1 một mình. Một lần nữa, thật dễ dàng: Chỉ cần gọi
$ python out.py
start show1
hello
in buffer: sys.stdout being buffered

start show2
hello
0 (hoặc tương đương) cho đến khi không còn đầu ra. Vì
$ python out.py
start show1
hello
in buffer: sys.stdout being buffered

start show2
hello
1 là luồng Python I/O bình thường, bạn có thể sử dụng tất cả các cấu trúc thông thường trên đó, như:

for line in proc.stdout:

Hoặc, một lần nữa, bạn có thể sử dụng

from cStringIO import StringIO
import os
import subprocess
import sys

def show1():
   print 'start show1'
   save = sys.stdout
   sys.stdout = StringIO()
   print 'sys.stdout being buffered'
   proc = subprocess.Popen(['echo', 'hello'])
   proc.wait()
   in_stdout = sys.stdout.getvalue()
   sys.stdout = save
   print 'in buffer:', in_stdout

def show2():
   print 'start show2'
   save = sys.stdout
   sys.stdout = open(os.devnull, 'w')
   print 'after redirect sys.stdout'
   proc = subprocess.Popen(['echo', 'hello'])
   proc.wait()
   sys.stdout = save

show1()
show2()
2, đơn giản là
$ python out.py
start show1
hello
in buffer: sys.stdout being buffered

start show2
hello
3 cho bạn.

Nếu bạn chỉ muốn chụp

for line in proc.stdout:
1, nó hoạt động giống như với
for line in proc.stdout:
0.

Có một mẹo nữa trước khi mọi thứ trở nên khó khăn. Giả sử bạn muốn chụp

for line in proc.stdout:
0, và cũng nắm bắt
for line in proc.stdout:
1 nhưng trên cùng một đường ống với stdout:

proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

Trong trường hợp này,

$ python out.py
start show1
hello
in buffer: sys.stdout being buffered

start show2
hello
8 "Cheat"! Chà, nó phải làm điều này, vì vậy nó không thực sự gian lận: nó bắt đầu quá trình phụ với cả stdout và stderr của nó được hướng vào bộ mô tả ống (đơn) cung cấp lại quy trình cha mẹ (Python) của nó. Về phía cha mẹ, một lần nữa chỉ có một bộ mô tả đường ống duy nhất để đọc đầu ra. Tất cả đầu ra "stderr" hiển thị trong
$ python out.py
start show1
hello
in buffer: sys.stdout being buffered

start show2
hello
9 và nếu bạn gọi
from cStringIO import StringIO
import os
import subprocess
import sys

def show1():
   print 'start show1'
   save = sys.stdout
   sys.stdout = StringIO()
   print 'sys.stdout being buffered'
   proc = subprocess.Popen(['echo', 'hello'])
   proc.wait()
   in_stdout = sys.stdout.getvalue()
   sys.stdout = save
   print 'in buffer:', in_stdout

def show2():
   print 'start show2'
   save = sys.stdout
   sys.stdout = open(os.devnull, 'w')
   print 'after redirect sys.stdout'
   proc = subprocess.Popen(['echo', 'hello'])
   proc.wait()
   sys.stdout = save

show1()
show2()
2, kết quả STDERR (giá trị thứ hai trong tuple) sẽ là
for line in proc.stdout:
2, không phải là một chuỗi.

Các trường hợp cứng: Hai hoặc nhiều đường ống

Tất cả các vấn đề xảy ra khi bạn muốn sử dụng ít nhất hai đường ống. Trên thực tế, mã

$ python out.py
start show1
hello
in buffer: sys.stdout being buffered

start show2
hello
8 có bit này:

def communicate(self, input=None):
    ...
    # Optimization: If we are only using one pipe, or no pipe at
    # all, using select() or threads is unnecessary.
    if [self.stdin, self.stdout, self.stderr].count(None) >= 2:

Nhưng, than ôi, ở đây chúng tôi đã thực hiện ít nhất hai, và có thể ba, các đường ống khác nhau, vì vậy subprocess.PIPE3 trả về 1 hoặc 0. Chúng ta phải làm mọi thứ một cách khó khăn.

Trên Windows, điều này sử dụng subprocess.PIPE4 để tích lũy kết quả cho subprocess.PIPE5 và subprocess.PIPE6 và có luồng cha mẹ cung cấp dữ liệu đầu vào subprocess.PIPE7 (và sau đó đóng đường ống).

Trên POSIX, điều này sử dụng subprocess.PIPE8 nếu có, nếu không subprocess.PIPE9, để tích lũy đầu ra và cung cấp đầu vào stdin. Tất cả điều này chạy trong quy trình/chủ đề cha mẹ (đơn).

Chủ đề hoặc cuộc thăm dò/chọn là cần thiết ở đây để tránh bế tắc. Ví dụ, giả sử rằng chúng tôi đã chuyển hướng cả ba luồng đến ba đường ống riêng biệt. Giả sử thêm rằng có một giới hạn nhỏ về số lượng dữ liệu có thể được nhét vào đường ống trước khi quá trình viết bị đình chỉ, chờ quá trình đọc "làm sạch" đường ống từ đầu kia. Hãy đặt giới hạn nhỏ đó cho một byte duy nhất, chỉ để minh họa. (Đây thực sự là cách mọi thứ hoạt động, ngoại trừ giới hạn đó lớn hơn nhiều so với một byte.)

Nếu quá trình cha mẹ (python) cố gắng viết một số byte, say, subprocess.Popen0to subprocess.Popen1, byte đầu tiên đi vào và sau đó lần thứ hai khiến quá trình Python đình chỉ, chờ quá trình phụ đọc byte đầu tiên, làm trống đường ống.

Trong khi đó, giả sử quá trình phụ quyết định in một "Xin chào! Đừng hoảng sợ!" Lời chào. subprocess.Popen2 đi vào đường ống stdout của nó, nhưng subprocess.Popen3 khiến nó bị đình chỉ, chờ cha mẹ của nó đọc subprocess.Popen2 đó, làm trống ống stdout.

Bây giờ chúng tôi bị mắc kẹt: Quá trình Python đang ngủ, chờ nói xong "đi", và quá trình phụ cũng đang ngủ, chờ nói xong "Xin chào! Đừng hoảng sợ!".

subprocess.Popen tránh được vấn đề này với luồng hoặc chọn/thăm dò ý kiến. Khi byte có thể đi qua các đường ống, chúng đi. Khi chúng không thể, chỉ có một chủ đề (không phải toàn bộ quá trình) phải ngủ hoặc trong trường hợp chọn/thăm dò ý kiến, quá trình Python chờ đồng thời "có thể viết" hoặc "dữ liệu có sẵn", ghi vào stdin của quy trình Chỉ khi có phòng, và chỉ đọc stdout và/hoặc stderr của nó chỉ khi dữ liệu đã sẵn sàng. Mã

from cStringIO import StringIO
import os
import subprocess
import sys

def show1():
   print 'start show1'
   save = sys.stdout
   sys.stdout = StringIO()
   print 'sys.stdout being buffered'
   proc = subprocess.Popen(['echo', 'hello'])
   proc.wait()
   in_stdout = sys.stdout.getvalue()
   sys.stdout = save
   print 'in buffer:', in_stdout

def show2():
   print 'start show2'
   save = sys.stdout
   sys.stdout = open(os.devnull, 'w')
   print 'after redirect sys.stdout'
   proc = subprocess.Popen(['echo', 'hello'])
   proc.wait()
   sys.stdout = save

show1()
show2()
2 (thực tế là subprocess.Popen7 trong đó các trường hợp có lông được xử lý) trả về một khi tất cả dữ liệu STDIN (nếu có) đã được gửi và tất cả dữ liệu stdout và/hoặc stderr đã được tích lũy.

Nếu bạn muốn đọc cả

for line in proc.stdout:
0 và
for line in proc.stdout:
1 trên hai đường ống khác nhau (bất kể chuyển hướng stdin), bạn cũng sẽ cần tránh bế tắc. Kịch bản bế tắc ở đây là khác nhau, nó xảy ra khi quy trình con viết một cái gì đó dài đến
for line in proc.stdout:
1 trong khi bạn đang lấy dữ liệu từ
for line in proc.stdout:
0 hoặc ngược lại, nhưng nó vẫn ở đó.


Bản demo

Tôi đã hứa sẽ chứng minh rằng, không được tái định hướng, Python

$ python out.py
start show1
hello
in buffer: sys.stdout being buffered

start show2
hello
8es viết cho stdout cơ bản, không phải
for line in proc.stdout:
3. Vì vậy, đây là một số mã:

from cStringIO import StringIO
import os
import subprocess
import sys

def show1():
   print 'start show1'
   save = sys.stdout
   sys.stdout = StringIO()
   print 'sys.stdout being buffered'
   proc = subprocess.Popen(['echo', 'hello'])
   proc.wait()
   in_stdout = sys.stdout.getvalue()
   sys.stdout = save
   print 'in buffer:', in_stdout

def show2():
   print 'start show2'
   save = sys.stdout
   sys.stdout = open(os.devnull, 'w')
   print 'after redirect sys.stdout'
   proc = subprocess.Popen(['echo', 'hello'])
   proc.wait()
   sys.stdout = save

show1()
show2()

Khi chạy:

$ python out.py
start show1
hello
in buffer: sys.stdout being buffered

start show2
hello

Lưu ý rằng thói quen đầu tiên sẽ thất bại nếu bạn thêm Popen5, vì đối tượng Popen6 không có

for line in proc.stdout:
8. Thứ hai sẽ bỏ qua Popen8 nếu bạn thêm Popen5 vì
for line in proc.stdout:
3 đã được chuyển hướng đến stdin1.

.

Làm thế nào để bạn thực hiện lệnh shell trong python và nhận đầu ra?

Nhận đầu ra từ lệnh shell bằng cách sử dụng lệnh con khởi chạy lệnh shell mà chúng tôi muốn thực thi bằng hàm subprocess.popen. Các đối số cho lệnh này là lệnh shell dưới dạng danh sách và chỉ định đầu ra và lỗi. Đầu ra từ quy trình con.Launch the shell command that we want to execute using subprocess. Popen function. The arguments to this command is the shell command as a list and specify output and error. The output from subprocess.

Làm cách nào để chạy một lệnh shell trong Python?

SubProcess.popen () Chúng tôi đang sử dụng quy trình con. Phương thức popen () để thực thi tập lệnh Echo Shell bằng Python. Bạn có thể đưa ra nhiều đối số hơn cho đối tượng hàm popen (), như shell = true, điều này sẽ làm cho lệnh chạy trong một shell riêng biệt. we are using the subprocess. Popen() method to execute the echo shell script using Python. You can give more arguments to the Popen function Object() , like shell=True, which will make the command run in a separate shell.

Làm thế nào để bạn lưu trữ đầu ra của một lệnh cho một biến trong Python?

Quá trình phụ Python.Sử dụng hàm SubProcess.check_output () Chúng ta có thể lưu trữ đầu ra trong một biến.Using subprocess. check_output() function we can store the output in a variable.

Làm thế nào để bạn in lệnh đầu ra trong Python?

Python: Nhận đầu ra lệnh hệ thống..
Giải pháp mẫu:-.
Mã python: Nhập quá trình phụ # Tệp và Danh sách thư mục returned_text = subprocess.check_output ("dir", shell = true
Flowchart:.
Trình chỉnh sửa mã Python:.