Làm thế nào để chuyển hướng đầu ra với quy trình con trong Python?


97

Những gì tôi làm trong dòng lệnh:

cat file1 file2 file3 > myfile

Những gì tôi muốn làm với python:

import subprocess, shlex
my_cmd = 'cat file1 file2 file3 > myfile'
args = shlex.split(my_cmd)
subprocess.call(args) # spits the output in the window i call my python program

Việc thực thi một lệnh như vậy trong quy trình con sẽ không cung cấp cho bạn bất kỳ đầu ra nào. Có thể bạn muốn chạy nó mà không cần > myfile chuyển hướng đầu ra từ cat file1 file2 file3 thành python?
PoltoS

@PoltoS Tôi muốn nối một số tệp và sau đó xử lý tệp kết quả. Tôi nghĩ sử dụng mèo là giải pháp thay thế dễ dàng nhất. Có cách nào tốt hơn / trăn trở để làm điều đó không?
catatemypythoncode

os.sendfile()có thể giải pháp dựa trên cơ sở, hãy xem Tạo lại lệnh mèo unix trong python
jfs

1
Tôi nghĩ rằng chuyển hướng đầu ra ('>' hoặc '>>') không hoạt động trong quy trình con. Mở (ít nhất là trong Python 2.7) (trong chế độ shell = True) Trong ví dụ này, như những người khác đã chỉ ra, bạn có thể khắc phục điều này bằng cách không sử dụng chuyển hướng, nhưng trong các trường hợp khác, chuyển hướng là hữu ích. Nếu chuyển hướng hoặc đường ống không được hỗ trợ trong subprocess.Popen được nên được ghi chép (và / hoặc os.system () nên không được phản đối cho đến khi điều này được cố định)
RIBO

Câu trả lời:


20

CẬP NHẬT: os.system không được khuyến khích, mặc dù vẫn có sẵn trong Python 3.


Sử dụng os.system:

os.system(my_cmd)

Nếu bạn thực sự muốn sử dụng quy trình con, đây là giải pháp (chủ yếu được lấy ra từ tài liệu cho quy trình con):

p = subprocess.Popen(my_cmd, shell=True)
os.waitpid(p.pid, 0)

OTOH, bạn có thể tránh hoàn toàn các cuộc gọi hệ thống:

import shutil

with open('myfile', 'w') as outfile:
    for infile in ('file1', 'file2', 'file3'):
        shutil.copyfileobj(open(infile), outfile)

1
Nó hoạt động, nhưng hãy để tôi hỏi bạn: Thư viện quy trình con có ích lợi gì nếu os.system đã hoàn thành công việc? Tôi có cảm giác lẽ ra nên sử dụng quy trình con thay vì đó là một thư viện dành riêng cho nhiệm vụ này, mặc dù vì tôi đang làm việc này chỉ vì bản thân nên lần này tôi sẽ ổn khi sử dụng os.system.
catatemypythoncode

Thư viện quy trình con linh hoạt hơn nhiều os.systemvà có thể lập mô hình os.systemchính xác, nhưng nó cũng phức tạp hơn để làm việc với.
Marcelo Cantos

13
os.systemđã đến trước đây subprocess. Cái trước là một API kế thừa mà cái sau dự định thay thế.
Ông già Noel

5
@catatemypythoncode: bạn không nên sử dụng os.system()hoặc shell=True. Để chuyển hướng đầu ra của một quy trình con, hãy sử dụng stdouttham số như trong câu trả lời của Ryan Thompson . Mặc dù bạn không cần quy trình con ( cat) trong trường hợp của mình, bạn có thể nối các tệp bằng Python thuần túy.
jfs

4
OTOH = Mặt khác
Cephlin

271

Trong Python 3.5+ để chuyển hướng đầu ra, chỉ cần chuyển một tệp điều khiển đang mở cho stdoutđối số tới subprocess.run:

# Use a list of args instead of a string
input_files = ['file1', 'file2', 'file3']
my_cmd = ['cat'] + input_files
with open('myfile', "w") as outfile:
    subprocess.run(my_cmd, stdout=outfile)

Như những người khác đã chỉ ra, việc sử dụng một lệnh bên ngoài như catcho mục đích này là hoàn toàn không liên quan.


9
Điều này sẽ là câu trả lời cho câu hỏi chung của đường ống khi sử dụng vỏ từ Python
Kaushik Ghose

46
Đây là câu trả lời đúng, không phải câu được đánh dấu là đúng.
Justin Blake

7
Đối với việc sử dụng Python 3.5+ subprocess.run(my_cmd, stdout=outfile)đang thay thếsubprocess.call(...)
Austin Yates

1
Đáng chú ý, điều này không làm việc với các đối tượng tập tin tùy chỉnh, nếu họ không có một lĩnh vực fileno (nếu họ không phải là một tập tin thực sự.)
Eliezer Miron

1
Vì Python <3.5 hiện không được dùng nữa nên tôi đã cập nhật câu trả lời với nhận xét của bạn, @AustinYates.
Greg Dubicki

5

@PoltoS Tôi muốn nối một số tệp và sau đó xử lý tệp kết quả. Tôi nghĩ sử dụng mèo là giải pháp thay thế dễ dàng nhất. Có cách nào tốt hơn / trăn trở để làm điều đó không?

Tất nhiên:

with open('myfile', 'w') as outfile:
    for infilename in ['file1', 'file2', 'file3']:
        with open(infilename) as infile:
            outfile.write(infile.read())

1
size = 'ffprobe -v error -show_entries format=size -of default=noprint_wrappers=1:nokey=1 dump.mp4 > file'
proc = subprocess.Popen(shlex.split(size), shell=True)
time.sleep(1)
proc.terminate() #proc.kill() modify it by a suggestion
size = ""
with open('file', 'r') as infile:
    for line in infile.readlines():
        size += line.strip()

print(size)
os.remove('file')

Khi bạn sử dụng quy trình con , quy trình phải bị hủy, đây là một ví dụ, nếu bạn không hủy quy trình, tệp sẽ trống và bạn không thể đọc được gì. Nó có thể chạy trên Windows. Tôi không thể đảm bảo rằng nó có thể chạy trên Unix.


1
Đó là một ví dụ mã xấu (nó sẽ không hoạt động trên Unix, nó thể hiện hủ tục for line in .readlines():, s +=) và proc.kill()có thể dẫn đến mất thông tin nói chung (nó không cho phép các tiến trình con để chấm dứt một cách duyên dáng (trên Unix) - nội dung unflushed bị mất ). Dù sao, lưu ý về bộ đệm là thích hợp hơn như một nhận xét.
jfs

Tôi chạy nó trên Windows là được (Vì kill cũng bằng với end trên Windows). Trên Unix có thể bạn nên sử dụng proc.termina (). @ JF Sebastian Tôi không có Hệ thống Unix trên máy tính của mình.
wyx

Nếu bạn đang sử dụng Windows, hãy thả shlex.split(), thả shell=True, thả >file, thả open(), v.v. và sử dụng stdout=PIPE, Timer(1, proc.terminate).start(); output = proc.communicate()[0]thay thế. Đây là ví dụ đầy đủ . Các giải pháp khác: Dừng quá trình đọc đầu ra bằng Python mà không bị treo? Lưu ý: không có yêu cầu nào trong câu hỏi rằng bạn cần phải kết thúc quy trình con theo cách thủ công - bạn có thể giải quyết các vấn đề khác, ví dụ: một quy trình có thể hoạt động khác nếu quy trình của nó là một tty nhưng nó lại lạc đề.
jfs

0

Một trường hợp thú vị là cập nhật tệp bằng cách nối tệp tương tự vào tệp đó. Sau đó, người ta sẽ không phải tạo một tệp mới trong quá trình này. Nó đặc biệt hữu ích trong trường hợp cần nối thêm một tệp lớn. Đây là một khả năng sử dụng dòng lệnh teminal trực tiếp từ python.

import subprocess32 as sub

with open("A.csv","a") as f:
    f.flush()
    sub.Popen(["cat","temp.csv"],stdout=f)
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.