2015-05-27 3 views
1

Как видно из названия говорит:Почему ln из подпроцесса Python выходит из строя, когда ему удается выполнить обычную командную строку?

>>> from subprocess import check_output 
>>> check_output(['ln', '~/other_folder/src/models/sc_models.py', './src/models/sc_models.py']) 
Traceback (most recent call last): 
    File "<input>", line 1, in <module> 
    File "/usr/lib/python2.7/subprocess.py", line 573, in check_output 
    raise CalledProcessError(retcode, cmd, output=output) 
CalledProcessError: Command '['ln', '~/other_folder/src/models/sc_models.py', './src/models/sc_models.py']' returned non-zero exit status 1 
>>> exit() 
$ ln ~/other_folder/src/models/sc_models.py ./src/models/sc_models.py 
$ 

Как это может быть? Как это может произойти из командной строки, но не удается выполнить вызов подпроцесса Python?

Все советы приветствуются!

+0

Попробуйте добавить команду 'shell = True' в команду check_output. – SwankSwashbucklers

+1

Не объединяйте' shell = True' со списком аргументов. – chepner

ответ

6

Вы должны использовать os.path.expanduser:

В Unix и Windows, возвращает аргумент с начальным компонентом ~ или ~ пользователь заменен на домашний каталог этого пользователя.

import os 

os.path.expanduser('~/other_folder/src/models/sc_models.py') 

In [2]: os.path.expanduser("~") 
Out[2]: '/home/padraic' 

Python ищет каталог с именем ~ в ваших Д, который, очевидно, терпит неудачу. Когда вы запускаете код из bash, ~ расширяется, если только вы не должны использовать shell=True, где команда будет передана оболочке, а оболочка будет расширять тильду, тогда вам нужно будет использовать os.path.expanduser или передать весь путь ie/home/user/other_folder ...... Я хотел бы использовать shell = False с os.path.expanduser("~").

+0

Примечание: код в вопросе не будет работать, даже если вы должны добавить 'shell = True', потому что только первый элемент списка выполняется как команда оболочки, а остальные интерпретируются как аргументы оболочки в POSIX. Другими словами: не используйте аргумент list и 'shell = True' вместе, передайте строку вместо или (лучше) не используйте' shell = True': как вы показали, достаточно вызвать 'os. path.expanduser ('~/...') 'здесь. – jfs

+0

@ J.F.Sebastian, почему 'check_call ([" ls "," ~/"], shell = True)' work then? –

+0

Вы понимаете разницу между 'sh -c 'cmd arg1'' (правильный) и' sh -c' cmd 'arg1' (неправильный)? Например, см. Http://bugs.python.org/issue7839 – jfs