2013-04-03 31 views
8

Tôi đang cố gắng in danh sách các bộ dữ liệu được định dạng trong số stdout của tôi. Đối với điều này, tôi sử dụng phương pháp str.format. Tất cả mọi thứ hoạt động tốt, nhưng khi tôi đường ống đầu ra để xem các dòng đầu tiên bằng cách sử dụng lệnh head một số IOError xảy ra.Làm cách nào để tránh lỗi ống bị hỏng khi in một lượng lớn dữ liệu được định dạng?

Đây là mã của tôi:

# creating the data 
data = []$ 
for i in range(0, 1000):            
    pid = 'pid%d' % i 
    uid = 'uid%d' % i 
    pname = 'pname%d' % i 
    data.append((pid, uid, pname)) 

# find max leghed string for each field 
pids, uids, pnames = zip(*data) 
max_pid = len("%s" % max(pids)) 
max_uid = len("%s" % max(uids)) 
max_pname = len("%s" % max(pnames)) 

# my template for the formatted strings 
template = "{0:%d}\t{1:%d}\t{2:%d}" % (max_pid, max_uid, max_pname) 

# print the formatted output to stdout 
for pid, uid, pname in data: 
    print template.format(pid, uid, pname) 

Và đây là lỗi tôi nhận được sau khi chạy lệnh: python myscript.py | head

Traceback (most recent call last): 
    File "lala.py", line 16, in <module> 
    print template.format(pid, uid, pname) 
IOError: [Errno 32] Broken pipe 

bất cứ ai có thể giúp tôi về vấn đề này?

Tôi cố gắng để đưa print trong một khối try-except để xử lý các lỗi, nhưng sau đó là một thông báo trong giao diện điều khiển:

close failed in file object destructor: 
sys.excepthook is missing 
lost sys.stderr 

Tôi cũng đã cố gắng để tuôn ra ngay lập tức các dữ liệu thông qua một hai liên tiếp sys.stdout.writesys.stdout.flush cuộc gọi, nhưng không có gì happend ..

+2

Điều này xảy ra vì 'đầu' * đóng *' stdout', khiến 'in' thử và ghi vào tệp đã đóng. Bạn muốn thay thế điều gì? –

+0

Ok, cảm ơn bạn! Tôi muốn tránh việc in các thông điệp đó trong bảng điều khiển. Tôi muốn sử dụng một biến thể của mã này cho một công cụ dòng lệnh. –

+1

Câu hỏi này có thể trùng lặp; xem: http://stackoverflow.com/questions/11423225/why-does-my-python3-script-balk-at-piping-its-output-to-head-or-tail-sys-module –

Trả lời

10

head đọc từ stdout sau đó đóng nó. Điều này gây ra print để thất bại, nội bộ nó viết đến sys.stdout, hiện đã đóng.

Bạn có thể chỉ đơn giản là bắt các IOError và thoát âm thầm:

try: 
    for pid, uid, pname in data: 
     print template.format(pid, uid, pname) 
except IOError: 
    # stdout is closed, no point in continuing 
    # Attempt to close them explicitly to prevent cleanup problems: 
    try: 
     sys.stdout.close() 
    except IOError: 
     pass 
    try: 
     sys.stderr.close() 
    except IOError: 
     pass 
+0

ok trong đơn giản này chương trình này hoạt động, nhưng trong công cụ dòng lệnh đôi khi hoạt động và đôi khi xảy ra một lần nữa thông báo này: 'đóng thất bại trong tập tin đối tượng destructor: sys.excepthook là mất tích mất sys.stderr' –

+0

@ThanasisPetsas: Tìm thấy một công việc xung quanh điều đó nữa. –

+0

Haha! Tôi tìm thấy nó quá trong một số câu trả lời tại stackoverflow! tôi đã thử nó nhưng nó không hoạt động! Có vẻ như có một điều kiện chủng tộc .. Nhưng tôi không thể tìm ra cách giải quyết nó .. –

1

Các hành vi bạn đang nhìn thấy được liên kết với việc thực hiện sản lượng đệm trong Python3. Vấn đề có thể tránh được bằng cách sử dụng tùy chọn -u hoặc thiết lập biến môi trường PYTHONUNBUFFERED = x. Xem trang hướng dẫn sử dụng để biết thêm thông tin về -u.

$ python2.7 testprint.py | echo 

Exc: <type 'exceptions.IOError'> 
$ python3.5 testprint.py | echo 

Exc: <class 'BrokenPipeError'> 
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> 
BrokenPipeError: [Errno 32] Broken pipe 
$ python3.5 -u testprint.py | echo 

Exc: <class 'BrokenPipeError'> 
$ export PYTHONUNBUFFERED=x 
$ python3.5 testprint.py | echo 

Exc: <class 'BrokenPipeError'> 
+0

Yup, nhưng tôi đã có vấn đề này trong Python2.7. Tôi không sử dụng Python3. –

0

Nói chung, tôi cố gắng nắm bắt được lỗi cụ thể nhất mà tôi có thể tránh được. Trong trường hợp này nó là BrokenPipeError:

try: 
    # I usually call a function here that generates all my output: 
    for pid, uid, pname in data: 
     print template.format(pid, uid, pname) 
except BrokenPipeError as e: 
    pass # Ignore. Something like head is truncating output. 
finally: 
    sys.stderr.close() 

Nếu đây là vào cuối thực hiện, tôi thấy tôi chỉ cần phải đóng sys.stderr. Nếu tôi không đóng sys.stderr, tôi sẽ nhận được một BrokenPipeError nhưng không có dấu vết ngăn xếp.

Điều này có vẻ là bản sửa lỗi tối thiểu để viết các công cụ xuất ra đường ống.

1

Đã xảy ra sự cố này với Python3 và gỡ lỗi ghi nhật ký cũng được chuyển vào đầu. Nếu kịch bản của bạn nói chuyện với mạng hoặc không tập tin IO, chỉ cần thả IOError của không phải là một giải pháp tốt. Mặc dù có đề cập ở đây, tôi không thể bắt được BrokenPipeError vì một lý do nào đó.

Tìm thấy một bài đăng blog nói về khôi phục xử lý tín hiệu mặc định cho SIGPIPE: http://newbebweb.blogspot.com/2012/02/python-head-ioerror-errno-32-broken.html

Nói tóm lại, bạn thêm dòng sau vào kịch bản của bạn trước khi phần lớn các đầu ra:

if log.isEnabledFor(logging.DEBUG): # optional 
    # set default handler to no-op 
    from signal import signal, SIGPIPE, SIG_DFL 
    signal(SIGPIPE, SIG_DFL) 

Điều này dường như xảy ra với đầu, nhưng không phải các chương trình khác như grep --- như đã đề cập đầu đóng stdout. Nếu bạn không thường xuyên sử dụng kịch bản, nó có thể không đáng lo ngại.

+1

Tuyệt vời! Cảm ơn lời giải thích và bài viết! –

Các vấn đề liên quan