LINUX.ORG.RU

Парсинг stdout в Python

 ,


0

1

Хочу спарсить вывод такой команды

pv -n dump.sql | mysql -uroot -ppass -h127.0.0.1 dbname
Нужно это для того что бы иметь прогресс импорта в процентах. Гугл выдает парсинги с помощью subprocess.Popen с простыми командами типа «ls -la». Пробовал и так
pv_cmd = subprocess.Popen(['pv', '-n', 'dump.sql'], shell=True, stdout=subprocess.PIPE)
mysql_cmd = subprocess.Popen(['mysql', '-uroot', '-ppass', '-h127.0.0.1', 'dbname'], shell=True, stdin.pv_cmd.stdout, stdout=subprocess.PIPE)
Ругается «SyntaxError: non-keyword arg after keyword arg».


Ответ на: комментарий от proud_anon

Да, только что увидел эту ошибку, но сейчас почему то ругается

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

Хотя я ему дал креды удаленного мускуля. Где то он их не подхватывает что ли.

OxFF
() автор топика
Ответ на: комментарий от proud_anon

ну я естественно это сделал :) Да и если бы проблема была в этом, он бы не ругался на локальный сокет.

OxFF
() автор топика
Ответ на: комментарий от OxFF

Я не работал с MySQL. Наверное, надо смотреть в сторону различий в переменных среды.

И ещё. Почему у тебя shell=True? Тебе реально надо запускать это в шелле, а не просто так? Это, кстати, может быть причиной проблемы.

proud_anon ★★★★★
()
Последнее исправление: proud_anon (всего исправлений: 1)
Ответ на: комментарий от proud_anon

Без shell=True взлетело, но все равно stdout идет просто на экран я вижу циферки но не вижу print который делаю что бы понять что питон это ловит.

OxFF
() автор топика
Ответ на: комментарий от buratino

ну так оно выполнится, туда запишет аутпут и потом выведет, а мне нужно в момент выполнения эти состояния перехватывать, в реалтайме аутпут брать.

OxFF
() автор топика
Ответ на: комментарий от buratino
root@dev:~# python test001.py 
51
51
100
progress
import os
def execute(command):
    return os.popen(command).read()

print "progress" + execute('pv -n dump.sql | mysql -uroot -ppass -h111.111.111.111 dbname')
OxFF
() автор топика
#!/usr/bin/python3

import sys
import time
import subprocess

if len(sys.argv) == 2:
  if sys.argv[1] == 'prog1':
    for i in range(10):
      sys.stdout.write('%i\n' % i)
      sys.stdout.flush()
      time.sleep(1)
  else:
    for line in sys.stdin:
      sys.stdout.write('>%s' % line)
else:
  p1 = subprocess.Popen(['./run.py', 'prog1'],
                          stdout=subprocess.PIPE)
  p2 = subprocess.Popen(['./run.py', 'prog2'], stdin=p1.stdout)
  p1.stdout.close()
  p2.communicate()
anonymous
()
Ответ на: комментарий от anonymous

насколько я понимаю communicate() будет ждать завершения. Многие примеры описывают ситуацию когда грубо говоря мгновенный вывод какой то программы записывают в переменную. Мне же нужно писать stdout по мере появления, то есть я хочу ловить цифры прогресса импорта из stdout и писать их в redis по мере появления, а не после окончания работы импорта.

Вот я запускаю импорт и у меня в stdout начинают идти цифры:

0
1
2
3
4
5
...
соотвественно я хочу:
0 -> publish to redis
1 -> publish to redis
... 

OxFF
() автор топика
Ответ на: комментарий от OxFF

соотвественно я хочу:

Ничего непонял, можешь указать конкретней что в примере не нравится? В исходном два процесса связаны пайпом в реальном времени.

communicate() будет ждать завершения

Это касается только внешнего к связанным процессам процесса. Буквально A запускает B и C, затем связывает stdout B с stdin С и ждет, когда же завершится процесс C.

Хочешь из процесса C получать данные, получай, никто не запрещал аналогично связаться с C процессом:

#!/usr/bin/python3

import sys
import time
import subprocess

if len(sys.argv) == 2:
  if sys.argv[1] == 'prog1':
    for i in range(10):
      sys.stdout.write('%i\n' % i)
      sys.stdout.flush()
      time.sleep(0.5)
  else:
    for line in sys.stdin:
      sys.stdout.write('>%s' % line)
      sys.stdout.flush()
else:
  script = sys.argv[0]
  python = sys.executable
  p1 = subprocess.Popen([
    python, script, 'prog1'],
    stdout=subprocess.PIPE
  )
  p2 = subprocess.Popen([
    python, script, 'prog2'],
    stdin=p1.stdout,
    stdout=subprocess.PIPE
  )
  for line in p2.stdout:
    line = line.strip().decode('utf-8')
    print('%s -> pusblish to redis' % line)

anonymous
()
Ответ на: комментарий от anonymous

Вывод:

root@dev:~# python test001.py 
0
0
0
0
0
0
0
0
0
0
0
0
0
1
1
1
1
и т.д.

Скрипт:

import subprocess

pv_cmd = ['pv', '-n', 'dump.sql']
mysql_cmd = ['mysql', '-uroot', '-ppass', '-h111.111.111.111', 'dbname']

p1 = subprocess.Popen(pv_cmd, stdout=subprocess.PIPE)
p2 = subprocess.Popen(mysql_cmd, stdin=p1.stdout, stdout=subprocess.PIPE)

for line in p2.stdout:
    line = line.strip().decode('utf-8')
    print '%s -> pusblish to redis' % line

Не пойму что я делаю не так. Во всех нагугленных стаковерфлоу и тд аналогично все считывают, у меня оно игнорит print '%s -> pusblish to redis' % line и продолжает просто сыпать циферки на экран.

OxFF
() автор топика
Ответ на: комментарий от OxFF

Тебе уже об этом намекали:

А точно не в stderr?

В приведенном выше скрипте, в части prog1, поменяй в двух строчках stdout на stderr, тогда наглядно увидишь то, что у тебя происходит:

-       sys.stdout.write('%i\n' % i)
-       sys.stdout.flush()
+       sys.stderr.write('%i\n' % i)
+       sys.stderr.flush()

anonymous
()
Ответ на: комментарий от anonymous

видать я совсем тугой, не могу догнать нафига мне этот кусок кода

if len(sys.argv) == 2:
  if sys.argv[1] == 'prog1':
    for i in range(10):
      sys.stdout.write('%i\n' % i)
      sys.stdout.flush()
      time.sleep(0.5)
  else:
    for line in sys.stdin:
      sys.stdout.write('>%s' % line)
      sys.stdout.flush()
else:
  script = sys.argv[0]
  python = sys.executable

OxFF
() автор топика
Ответ на: комментарий от OxFF

это пример, нет у меня желания создавать минимальный пример с реальными pv и mysql. считай pv - это prog1, а mysql - prog2.

anonymous
()
Ответ на: комментарий от OxFF

Тебе примерно так надо делать:

#!/usr/bin/python3

import sys
import time
import subprocess
from select import select

if len(sys.argv) == 2:
  if sys.argv[1] == 'prog1':
    for i in range(10):
      sys.stdout.write('data: %i\n' % i)
      sys.stdout.flush()
      sys.stderr.write('%i\n' % i)
      sys.stderr.flush()
      time.sleep(0.5)
  else:
    for line in sys.stdin:
      sys.stdout.write('>%s' % line)
      sys.stdout.flush()
      if line == 'data: 4\n':
        sys.stderr.write('error: >>>%s<<<\n' % line.strip())
        sys.stderr.flush()
else:
  script = sys.argv[0]
  python = sys.executable
  p1_args = [python, script, 'prog1']
  p2_args = [python, script, 'prog2']
  p1 = subprocess.Popen(p1_args,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE
  )
  p2 = subprocess.Popen(p2_args,
    stdin=p1.stdout,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE
  )
  lst = [p1.stderr, p2.stderr, p2.stdout]
  while lst:
    rds, wds, eds = select(lst, [], [])
    for stderr in rds:
      line = stderr.readline()
      if line == b'':
        lst.remove(stderr)
      elif stderr == p1.stderr:
        print('%s -> pusblish to redis from p1' % line)
      elif stderr == p2.stdout:
        print('%s -> pusblish to redis from p2.out' % line)
      elif stderr == p2.stderr:
        print('%s -> pusblish to redis from p2.err' % line)
только заменить:
  p1_args = [python, script, 'prog1']
  p2_args = [python, script, 'prog2']
на свои:
  p1_args = ['pv', '-n', 'dump.sql']
  p2_args = ['mysql', '-uroot', '-ppass', '-h111.111.111.111', 'dbname']
и лишнее удалить

anonymous
()
Ответ на: комментарий от anonymous

Спасибо, но что то лайн все равно пустой так как

root@dev:~# python test001.py 
0
 -> pusblish to redis from p1
0
 -> pusblish to redis from p1
0
 -> pusblish to redis from p1
0
 -> pusblish to redis from p1

OxFF
() автор топика
Ответ на: комментарий от anonymous

неа, все равно ничего нет, причем поскольку стандартного аутпута тоже нет я вывел print line, и тоже пусто, в переменной ничего нет.

OxFF
() автор топика
Ответ на: комментарий от anonymous

Да, нашел где поменял код и обратно не вернул, сейчас вроде работает как надо. Огромное тебе спасибо :)

OxFF
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.