2011-12-21 27 views
5

Tôi đang viết một chương trình hiển thị văn bản trên thiết bị đầu cuối bằng cách sử dụng Unix ít hơn (1). Đây là phần có liên quan:Đầu vào không thành công sau khi giết ít hơn (1) subprocess

less = subprocess.Popen(['less -F -'], stdin=subprocess.PIPE, 
      stdout=sys.stdout, shell=True) 
try: 
    less.stdin.write(rfc_text) 
    less.stdin.flush() 
    less.stdin = sys.stdin 
    less.wait() 
except IOError: 
    less.terminate() 
    return errno.EPIPE 
except KeyboardInterrupt: 
    less.terminate() 
    return 0 

Trong khi chờ đợi ít hơn để kết thúc, tôi lắng nghe ngoại lệ cho bàn phím. Nếu tôi bắt được một, tôi sẽ giảm ít hơn với tín hiệu SIGTERM và thoát khỏi chương trình của tôi.

Bây giờ, khi điều đó xảy ra, tôi sẽ trở về dấu nhắc trình bao, nhưng trình bao không còn lặp lại những gì tôi viết và tôi phải đặt lại (1) để làm cho nó hoạt động trở lại.

Bất kỳ ý tưởng nào về cách làm cho ít chết hơn mà không dùng stdin của tôi với nó vào mộ? Toàn bộ nguồn có sẵn trên https://github.com/jforberg/rfc/blob/master/rfc.py

EDIT: Sau khi thử nghiệm, tôi đã phát hiện ra rằng cả mặc định (1) và man (1) đều bỏ qua đột quỵ C. Vì vậy, chỉ cần bỏ qua nó có thể là một lựa chọn khả thi. Tôi không chắc tôi nghĩ đó là cách thích hợp để làm điều đó mặc dù, vì vậy nếu ai đó có đề xuất tôi vẫn còn rất nhiều quan tâm.

+0

Là giải pháp thay thế rẻ, bạn có thể đặt 'os.system ('reset')' vào cuối tập lệnh. Các giải pháp thích hợp có thể sẽ liên quan đến việc ngăn chặn 'ít' lịch sự hơn, tức là viết một sigint và 'q' thành stdin của nó và sau đó chờ đợi nó hoàn thành. – wim

+0

@wim lại "giải pháp thích hợp của bạn": Tất nhiên! Ý nghĩ viết 'q' cho bản thân mình ít hơn đã không xảy ra với tôi. Ngay cả sau một thời gian lập trình Linux, tôi vẫn phải được nhắc nhở rằng mọi thứ đều là một tập tin. Hãy di chuyển nó vào một câu trả lời, và tôi sẽ chấp nhận nó. – jforberg

+2

Vì không có thủ thuật 'setpgid',' less' phải nằm trong cùng một nhóm tiến trình với quy trình Python của bạn, vì vậy nó sẽ nhận được cùng^C như quy trình Python của bạn.Tôi cho rằng nó cố gắng xử lý đặc biệt của riêng mình, mặc dù ... Làm thế nào về việc sử dụng '-e' (' --quit-at-eof') để nó sẽ thoát ra sau khi chương trình của bạn bị treo? – ephemient

Trả lời

1

Cách đơn giản nhất là yêu cầu người sử dụng để thoát less đúng (bằng cách nhấn q):

#!/usr/bin/env python 
from subprocess import PIPE, Popen 

p = Popen(['less'], stdin=PIPE) 
try: 
    p.communicate(''.join("%d\n" % i for i in range(1000))) 
except KeyboardInterrupt: 
    print("Press `q` to exit.") 
    p.wait() 
1

Về cơ bản có hai lựa chọn:

  1. Ít, con người và liên quan chương trình không chấm dứt khi kiểm soát-C, họ chỉ hủy bỏ bất kỳ hoạt động nào họ đang làm vào lúc này. Vì vậy, chỉ đơn giản là bỏ qua các phím tắt có vẻ là một lựa chọn. Điều này sẽ giữ lại tính năng hữu ích mà các hoạt động kéo dài, chẳng hạn như các tìm kiếm dài, có thể bị hủy bỏ mà không chấm dứt chương trình. Nó cũng là mong muốn cho chương trình hoạt động giống như các chương trình tương tự (trong trường hợp này là Unix).

  2. Ít chấp nhận tùy chọn -K sẽ làm cho nó chấm dứt khi điều khiển-C, giống như hầu hết các lệnh không tương tác.

0

Ah ah! Các giải pháp J.F. Sebastian là tốt, nhưng nó không hoạt động trong mọi trường hợp. Trong ứng dụng của tôi, tôi muốn sử dụng "less" như "tail -f" được thực hiện với "less + F -S logfilename". Người dùng phải nhấn CTRL + C để vào chế độ bình thường và họ Q để thoát.

Để quy trình này xảy ra không có vấn đề, tôi đã đưa ra các giải pháp 6 dòng sau (dựa trên J.F. đang Sebastian):

logpath = os.path.join(cwd, "filename.log") 
less = Popen(["less","+F","-S", logpath]) 
retcode = None 
while retcode is None: 
    try: retcode = less.wait() 
    except KeyboardInterrupt: pass 

Tôi nghĩ rằng đây giải quyết gốc. Nếu bạn nhập thứ gì đó ít hơn, bạn có thể phải tinh chỉnh phương thức Popen được sử dụng: wait() hoặc communicate(input).

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