Построчная удаленная передача данных в Python - PullRequest
2 голосов
/ 27 сентября 2010

Я играл с модулем subprocess для многократной отправки каждая строка во входном файле для процесса, созданного следующей командой.

ssh -t -A $host 'remote_command'

remote_command ожидает строку в своем STDIN, выполняет некоторую обработку на и повторяет цикл, пока STDIN не закроется или не достигнет EOF.

Чтобы достичь этого, я делал следующее:

process = subprocess.Popen("ssh -t -A $host 'remote_command'",
                           shell=True,
                           stdin=subprocess.PIPE)
for line in file('/tmp/foo'):
  process.stdin.write(line)
  process.stdin.flush()
process.stdin.close()

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

Ситуация такая же, когда я использую другой, хотя и очень похожий подход:

process = subprocess.Popen("ssh -t -A $host 'remote_command'",
                           shell=True,
                           stdin=file('/tmp/foo'))

Итак, вопрос: Как я могу убедиться, что каждая строка во входном файле отправляется, принимается и обрабатывается до конца удаленной машиной в Python?

Ответы [ 4 ]

2 голосов
/ 22 июня 2013

Если это ...

process = subprocess.Popen("ssh -t -A $host 'remote_command'",
                           shell=True,
                           stdin=subprocess.PIPE)
for line in file('/tmp/foo'):
    process.stdin.write(line)
    process.stdin.flush()
process.stdin.close()

... это вся ваша программа, она не будет (обязательно) работать.

Хотя последний вызов process.stdin.close() гарантирует, что все данные были отправлены в процесс ssh до завершения вашей программы, он не будет гарантировать, что процесс ssh отправил все данные по сети так что вполне может быть несколько выдающихся данных для отправки.

К сожалению, поскольку процесс ssh является дочерним процессом вашей программы, то, когда ваша программа завершает работу, процесс ssh получит SIGHUP, который немедленно уничтожит его, возможно, до того, как он завершит отправку всех своих данных .

Пока remote_command завершается при достижении EOF, это не проблема, и вы можете либо попросить процесс ssh игнорировать SIGHUP, и продолжить работу в фоновом режиме с ...

process = subprocess.Popen("nohup ssh -t -A $host 'remote_command'", ...)

... или попросите вашу программу дождаться завершения процесса ssh, добавив ...

process.wait()

... до конца вашей программы.


Обновление

При дальнейшем рассмотрении похоже, что процесс получает SIGHUP только в том случае, если завершается его управляющий tty, а не родительский процесс.

Это может быть связано с параметром -t, который создает новый управляющий tty на удаленном хосте, и он завершается до завершения подпроцесса, который он порождает.

В этом случае вам может понадобиться ...

process = subprocess.Popen("ssh -t -A $host 'nohup remote_command'", ...)

... или попробуйте без опции -t.

1 голос
/ 27 сентября 2010

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

return_code = p.wait()

Ваша удаленная команда, вероятно, должна вернуть 0 при успешном завершении и что-то не ноль, если произошла ошибка.

0 голосов
/ 26 июня 2013

Я бы сказал, что вам лучше всего использовать канал ответа, чтобы получить результаты удаленной команды и убедиться, что вы получаете подсказку между строками и после каждой строки. Кстати, я иногда обнаруживал, что фиктивная команда, такая как ls -l в конце сеанса удаленного соединения, помогает убедиться, что обработка завершена до разрыва соединения.

0 голосов
/ 27 сентября 2010

Вместо того, чтобы оборачиваться подпроцессом, вам, вероятно, будет лучше использовать что-то вроде paramiko .

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

...