Подпроцесс очень медленный при вызове внешнего egrep и меньше

Я пытаюсь создать скрипт python, который позволит мне динамически создавать атрибуты egrep -v и направлять вывод в меньшее (или большее количество).
Причина, по которой я хочу использовать внешний egrep+less, заключается в том, что файлы, которые я обрабатываю, представляют собой очень большие текстовые файлы (500 МБ+). Чтение их сначала в список и обработка всего через Python очень медленная.

Однако, когда я использую os.system или subprocess.call, все очень медленно в тот момент, когда я хочу выйти из меньшего вывода и вернуться к коду Python.

Мой код должен работать следующим образом:
1. ./myless.py messages_500MB.txt
2. Показывается вывод Less -FRX messages_500MB.txt (полный файл).
3 , Когда я нажимаю 'q', чтобы выйти из less -FRX, код Python должен вступить во владение и отобразить приглашение для пользователя ввести текст, который нужно исключить. Пользователь вводит его, и я добавляю его в список
4. Мой код на Python создает egrep -v 'exclude1' и направляет вывод в less
5. Пользователь повторяет шаг 3 и вводит еще что-то, что нужно исключить
6. Теперь мой код на Python вызывает egrep -v 'exclude1|exclude2' messages_500MB.txt | less -FRX
7. И процесс продолжается

Однако это не работает должным образом.
* На моем Mac, когда пользователь нажимает q, чтобы выйти из less -FRX, требуется несколько секунд для Отображается приглашение raw_input
* На машине с Linux я получаю множество сообщений 'egrep: write output: Broken pipe'
* Если (только для Linux) в less -FRX, я нажимаю CTRL+C, выходя из less -FRX почему-то становится намного быстрее (как и задумывалось). На Mac моя программа на Python ломается

Вот пример моего кода:

excluded = list()
myInput = ''
while myInput != 'q':
    grepText = '|'.join(excluded)
    if grepText == '':
        command = 'egrep "" ' + file + ' | less -FRX'
    else:
        command = 'egrep -v "' + grepText + '" ' + file + ' | less -FRX'

    subprocess.call(command, shell=True)
    myInput = raw_input('Enter text to exclude, q to exit, # to see what is excluded: ')
    excluded.append(myInput)

Любая помощь приветствуется


person Milos Kostic-Veljkovic    schedule 05.05.2015    source источник


Ответы (1)


На самом деле я понял, в чем проблема

Я провел некоторое исследование ошибок, которые видны при запуске моего скрипта в Linux ("egrep: запись вывода: Broken pipe"), и это привело меня к ответу:
Проблема в том, когда я использую файл egrep -v 'xyz' | меньше, когда я ухожу меньше, подпроцесс все еще продолжает работать, egrep и для больших файлов (500 МБ+) это занимает некоторое время.

Очевидно, подпроцесс берет две программы по отдельности и запускает первую (egrep) даже после выхода из второй (less)

Чтобы правильно решить мою проблему, я использую что-то вроде этого:

command = 'egrep -v "something" <filename>'
cmd2 = ('less', '-FRX') 
egrep = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
subprocess.check_call(cmd2, stdin=egrep.stdout)
egrep.terminate()

Направив первый процесс во второй процесс stdin, я теперь могу немедленно завершить egrep, когда я выйду из less, и теперь мой скрипт на python летает :)

Ура,
Milos

person Milos Kostic-Veljkovic    schedule 06.05.2015
comment
примечание: .terminate() завершает процесс оболочки (/bin/sh), дочерние процессы могут продолжать работать. См. Как завершить подпроцесс python, запущенный с помощью shell=True. Или еще лучше, запустите grep напрямую без оболочки. Вы также должны закрыть трубы, чтобы избежать утечек fd. См. раздел Как использовать subprocess.Popen для соединения нескольких процессов по каналам? - person jfs; 09.05.2015
comment
Спасибо, Себастьян. Это определенно то, что мне нужно изучить, чтобы улучшить сценарий, который я делаю для своей работы. ура за это - person Milos Kostic-Veljkovic; 15.05.2015