2016-03-07 9 views
1

Я хотел бы связаться с (удаленной) неинтерактивной оболочкой через stdin/stdout для запуска нескольких команд и чтения выходов. Проблема в том, что если я использую несколько команд на shell stdin, я не могу обнаружить границы между выходами отдельных команд.Запуск нескольких команд в неинтерактивном сеансе оболочки и анализ вывода

В Python-как псевдо-код:

sh = Popen(['ssh', '[email protected]', '/bin/bash'], stdin=PIPE, stdout=PIPE) 
sh.stdin.write('ls /\n') 
sh.stdin.write('ls /usr\n') 
sh.stdin.close() 
out = sh.stdout.read() 

Но очевидно out содержит выходы обеих команд сцепленных, и у меня нет никакого способа надежно их расщепления.

До сих пор моя лучшая идея состоит в том, чтобы вставить \0 байт между выходами:

sh.stdin.write('ls /; echo -ne "\0"\n') 
sh.stdin.write('ls /usr; echo -ne "\0"\n') 

Тогда я могу разделить out на нулевых символов.

Другие подходы, которые не работают для меня:

  • Я не хочу, чтобы запустить отдельный сеанс SSH за команду, как рукопожатие слишком тяжеловес.
  • Я бы предпочел не форсировать параметры ControlMaster на созданных оболочках, чтобы уважать ssh_config конечного пользователя.
  • Я бы предпочел, чтобы пользователям не требовалось устанавливать определенные серверные программы.

Есть ли лучший способ запуска нескольких команд за один сеанс и получения отдельных выходов? Существует ли широко развернутая оболочка с каким-то двоичным режимом вывода?

PS. Существует дубликат вопрос, но он не имеет удовлетворительного ответа: Run multiple commands in a single ssh session using popen and save the output in separate files

+1

Если вы можете запустить скрипт на удаленной системе, как Python, вы всегда можете передать команды на него, и есть их выходной закодированный в рассоле или JSON. Ваш подход кажется мне удобным, хотя если вы можете гарантировать, что вывод никогда не будет содержать нулевые символы. Это похоже на многокомпонентную кодировку mime, за исключением того, что использует граничные строки, которые обычно содержат длинные случайные символы, чтобы минимизировать вероятность конфликта. –

+1

Можете ли вы изменить свой процесс на цикл? Для каждой команды запишите команду, сбросьте буфер, затем прочитайте результаты? –

+1

Г-н.Llama, нет способа обнаружить, что выданная команда закончила работу (в отличие от просто работы для производства следующего фрагмента вывода). –

ответ

1

Для SSH я использовал paramiko и его метод invoke_shell для создания программно-управляемой экземпляр оболочки.

Ниже приведен не полный ответ, но он все еще взломан, но я считаю, что это шаг в правильном направлении.

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

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

Грубый пример:

from subprocess import Popen, PIPE 

sh = Popen('cmd', stdin=PIPE, stdout=PIPE) 
sh.stdin.write(b'F:\r\n') 
sh.stdin.write(b"if not %errorlevel% == 0 exit\r\n") 
sh.stdin.write(b'cd F:\\NewFolder\r\n') 
sh.stdin.write(b"if not %errorlevel% == 0 exit\r\n") 
sh.stdin.write('...some useful command with the current directory confirmed as set to F:\NewFolder...') 
sh.stdin.close() 
out = sh.stdout.read() 
sh.stdout.close() 
# Split 'out' by each line that ends with 'if not %errorlevel% == 0 exit' and do what you require with the responses