2014-07-29 7 views
1

Я использую subprocess.Popen для выполнения команды OS. Вот что я пытаюсь подражать в моем коде:Проблема с subprocess.Popen и выполнение команды ssh

ssh -T myhost < /path/to/some/file 

Он отлично работает так:

def runWorkerCode(filer, filename): 
    command = "/usr/bin/ssh -T " + filer + " < /devel/myscript" 
    try: 
     p = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True) 
     out, _ = p.communicate() 
    except Exception: 
     print "Error: %s" % Exception 
     sys.exit(1) 
    return out.rstrip().split('\n') 

Но следующие вызовы на Popen не работают:

 p = subprocess.Popen(["/usr/bin/ssh", "-T", filer, "<", "/devel/myscript"], stdout=subprocess.PIPE, shell=True) 
     p = subprocess.Popen(["/usr/bin/ssh -T", filer, "< /devel/myscript"], stdout=subprocess.PIPE, shell=True) 

I попробовал несколько других комбинаций, но только метод, с которым я могу работать, - это определить командную переменную и предоставить ее только Popen(). Я также пробовал shell=False.

Первый метод работает, но последний подход кажется мне «чище».

Почему нет Popen Позвольте мне указать аргументы в списке?

+0

В какой ОС вы находитесь? – wnnmaw

+0

Это будет работать на хостах Linux и Solaris (как sparc, так и x86). – BenH

ответ

2

Когда вы используете shell=True в UNIX, вы должны указать свои аргументы в виде строки. Когда вы предоставляете список, subprocess интерпретирует первый элемент в списке как всю вашу командную строку, а остальные элементы в списке в качестве аргументов передаются самой оболочке, а не вашей команде. Итак, в приведенном выше примере у вас заканчивается примерно так:

/bin/sh -T filer < /dev/myscript -c "/usr/sbin/ssh" 

Определенно не то, что вы имели в виду!

И наоборот, когда вы используете shell=False, вы можете передавать только строку, если вы используете одну команду без аргументов. Если у вас есть аргументы, нужно передать comamnd как последовательность. Вы также не можете использовать перенаправление оболочки через символ <, потому что в нем нет оболочки.

Если вы хотите использовать shell=False, вы можете использовать аргумент stdin ключевое слово, чтобы передать дескриптор файла /dev/myscript:

f = open("/dev/myscript") 
p = subprocess.Popen(["/usr/bin/ssh", "-T", filer], stdout=subprocess.PIPE, stdin=f, shell=False) 

правила для когда передать строку vs. когда пройти последовательность довольно путают, особенно когда вы привносите Windows в микс. Я бы внимательно прочитал documentation, чтобы попытаться понять все это. Проверьте как раздел на args, так и раздел на shell.

+0

Это не то, что говорят документы: «args требуется для всех вызовов и должна быть строкой или последовательностью аргументов программы. Обычно рекомендуется последовательность аргументов, поскольку она позволяет модулю заботиться о любом требуемом экранировании и цитирование аргументов (например, чтобы разрешить пробелы в именах файлов). ** Если передача одной строки, либо оболочка должна быть '' 'True''' (см. ниже), либо строка должна просто называть исполняемую программу без указания любые аргументы. ** « – wnnmaw

+1

@wnnmaw Я думаю, что это более актуально *« В Unix с оболочкой = True оболочка по умолчанию имеет значение/bin/sh. Если args - это строка, строка указывает команду для выполнения через оболочку. Это означает, что строка должна быть отформатирована точно так же, как и при вводе ее в командной строке. К ней относятся, например, кавычки или обратная косая черта, пропускающие имена файлов с пробелами в них. ** Если args - это последовательность, первый элемент указывает команду строка и любые дополнительные элементы будут рассматриваться как дополнительные аргументы самой оболочки. ** "*. Поскольку он предполагает, что вы * можете * передать последовательность с 'shell = True'. – dano

+2

@wnnmaw Однако документы также говорят об этом: «Если shell имеет значение« Истина », рекомендуется передавать args как строку, а не как последовательность». Я отредактирую свой ответ, чтобы попытаться прояснить ситуацию. – dano

Смежные вопросы