Как передать STDIN непосредственно в Python и разобрать, как grep? - PullRequest
2 голосов
/ 27 сентября 2019

Я пытаюсь выполнить регулярное подстановку в стиле sed / awk с помощью модуля python3 re.

Вы можете видеть, что он отлично работает здесь с жестко закодированной тестовой строкой:

#!/usr/bin/env python3

import re

regex = r"^(?P<time>\d+\:\d+\:\d+\.\d+)(?:\s+)(?P<func>\S+)(?:\s+)(?P<path>\S+(?: +\S+)*?)(?:\s+)(?P<span>\d+\.\d+)(?:\s+)(?P<npid>(?P<name>\S+(?: +\S+)*?)\.(?P<pid>\d+))\n"
subst = "'\\g<name>', "

line = ("21:21:54.165651  stat64   this/                       0.000012         THiNG1.12471\n"
        "21:21:54.165652  stat64   /that                       0.000012         2thIng.12472\n"
        "21:21:54.165653  stat64   /and/the  other  thing.xml  0.000012  With  S paces.12473\n"
        "21:21:54.165654  stat64   /and/the_other_thing.xml    0.000012    without_em_.12474\n"
        "21:59:57.774616  fstat64           F=90               0.000002            tmux.4129\n")

result = re.sub(regex, subst, line, 0, re.MULTILINE)

if result:
        print(result)

Но у меня возникли проблемы с тем, чтобы он работал так же, как и со стандартным вводом:

#!/usr/bin/env python3

import sys, re

regex = r"^(?P<time>\d+\:\d+\:\d+\.\d+)(?:\s+)(?P<func>\S+)(?:\s+)(?P<path>\S+(?: +\S+)*?)(?:\s+)(?P<span>\d+\.\d+)(?:\s+)(?P<npid>(?P<name>\S+(?: +\S+)*?)\.(?P<pid>\d+))\n"
subst = "'\\g<name>', "

for line in str(sys.stdin):
        #sys.stdout.write(line)
        result = re.sub(regex, subst, line, 0, re.MULTILINE)

if result:
        print(result,end='')

Я хотел бы иметь возможность транслировать ввод напрямуюв него из другой утилиты, как это обычно бывает с grep и аналогичными утилитами CLI.

Есть идеи, в чем тут проблема?


Приложение

Я пытался сделать вопрос простым и обобщенным в надежде, что ответы могут быть более полезными в подобныхно разные ситуации и полезны для большего количества людей.Тем не менее, детали могут пролить свет на проблему, поэтому я включу здесь точные детали моего текущего сценария:

На самом деле желаемый вход в мой скрипт - это поток вывода из утилиты fs_usage, он похож на утилиты типа ps, но обеспечивает постоянный поток системных вызовов и операций с файловой системой.Он сообщает вам, какие файлы считываются, записываются и т. Д. В режиме реального времени.

Из руководства:

NAME
fs_usage - сообщать о системных вызовахи сбои страниц, связанные с активностью файловой системы в режиме реального времени

ОПИСАНИЕ
Утилита fs_usage постоянно отображает информацию об использовании системных вызовов, относящуюся к активности файловой системы.Это требует привилегий root из-за средства трассировки ядра, которое он использует для работы.

По умолчанию отслеживаемая активность включает в себя все системные процессы, кроме:
fs_usage, Terminal.app, telnetd, telnet, sshd, rlogind, tcsh,csh, sh, zsh.Эти значения по умолчанию могут быть переопределены так, что вывод ограничивается включением или исключением (-e) списка процессов, указанных пользователем.

Вывод, представленный fs_usage, форматируется в соответствии с размером вашего окна.
В узком окне будет отображаться меньше столбцов.Используйте максимальное окно для максимального отображения данных.
Вы можете переопределить ограничения форматирования, принудительно установив широкий дисплей с помощью опции -w.
В этом случае отображаемые данные будут перенесены, когда окно недостаточно широкое.

Я собираю грубый маленький скрипт bash, чтобы вырвать имена процессов из потока и вывести их во временный файл журнала.Вы можете думать об этом как о фильтре или экстракторе.Здесь это как функция, которая выдает дамп прямо в стандартный вывод (удаляет комментарий к последней строке для выгрузки в файл).

proc_enum ()
  {
  while true; do
  sudo fs_usage -w -e 'grep' 'awk' | 
    grep -E -o '(?:\d\.\d{6})\s{3}\S+\.\d+' | 
    awk '{print $2}' | 
    awk -F '.' '{print $1}' \
      #>/tmp/proc_names.logx
  done
  }

Полезные ссылки

1 Ответ

0 голосов
/ 28 сентября 2019

Проблема str(sys.stdin) в том, что Python будет делать в цикле for, заключается в следующем:

 i = iter(str(sys.stdin))
 # then in every iteration
 next(i)

Здесь вы конвертируете метод в str, в результате мой компьютер:

str(sys.stdin) == "<_io.TextIOWrapper name='<stdin>' mode='r' encoding='cp1256'>"

вы не зацикливаетесь на строках, полученных stdin, вы зацикливаетесь на строковом представлении функции.

И еще одна проблема в первом примере: вы применяете re.sub ко всемутекст, но здесь вы применяете для каждой строки, поэтому вы должны объединить результат каждой строки или объединить строки в один текст перед применением re.sub.

import sys, re

regex = r"^(?P<time>\d+\:\d+\:\d+\.\d+)(?:\s+)(?P<func>\S+)(?:\s+)(?P<path>\S+(?: +\S+)*?)(?:\s+)(?P<span>\d+\.\d+)(?:\s+)(?P<npid>(?P<name>\S+(?: +\S+)*?)\.(?P<pid>\d+))\n"
subst = "'\\g<name>', "

result = ''
for line in sys.stdin:
    # here you should convert the input but I think is optional
    line = str(line)
    result += re.sub(regex, subst, line, 0, re.MULTILINE)


if result:
    print(result, end='')
...