Стандартный выход подпроцесса трубы к переменной
Я хочу запустить команду в pythong
, используя модуль подпроцесса и сохранить вывод в переменной. Однако я не хочу, чтобы вывод команды был распечатан на терминал.
Для этого кода:
def storels():
a = subprocess.Popen("ls",shell=True)
storels()
Я получаю список каталогов в терминале, вместо того, чтобы хранить его в a
. Я также пробовал:
def storels():
subprocess.Popen("ls > tmp",shell=True)
a = open("./tmp")
[Rest of Code]
storels()
Это также выводит вывод ls на мой терминал. Я даже пробовал эту команду с несколько устаревшим способом os.system, так как запуск ls > tmp
в терминале вообще не печатает ls
на терминал, а сохраняет его в tmp
. Однако происходит то же самое.
Edit:
Я получаю следующую ошибку после следующих рекомендаций marcog, но только при запуске более сложной команды. cdrecord --help
. Python выплевывает это:
Traceback (most recent call last):
File "./install.py", line 52, in <module>
burntrack2("hi")
File "./install.py", line 46, in burntrack2
a = subprocess.Popen("cdrecord --help",stdout = subprocess.PIPE)
File "/usr/lib/python2.6/subprocess.py", line 633, in __init__
errread, errwrite)
File "/usr/lib/python2.6/subprocess.py", line 1139, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
Ответы
Ответ 1
Чтобы получить вывод ls
, используйте stdout=subprocess.PIPE
.
>>> proc = subprocess.Popen('ls', stdout=subprocess.PIPE)
>>> output = proc.stdout.read()
>>> print output
bar
baz
foo
Команда cdrecord --help
выводит на stderr, поэтому вам нужно подключить этот узел. Вы также должны разбить команду на список токенов, как я сделал ниже, или альтернативный вариант - передать аргумент shell=True
, но он запускает полностью раздутую оболочку, которая может быть опасна, если вы не контролируете содержимое командной строки.
>>> proc = subprocess.Popen(['cdrecord', '--help'], stderr=subprocess.PIPE)
>>> output = proc.stderr.read()
>>> print output
Usage: wodim [options] track1...trackn
Options:
-version print version information and exit
dev=target SCSI target to use as CD/DVD-Recorder
gracetime=# set the grace time before starting to write to #.
...
Если у вас есть команда, которая выводит на stdout и stderr, и вы хотите их объединить, вы можете сделать это, перейдя stderr в stdout, а затем поймав stdout.
subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Как упоминалось Chris Morgan, вы должны использовать proc.communicate()
вместо proc.read()
.
>>> proc = subprocess.Popen(['cdrecord', '--help'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> out, err = proc.communicate()
>>> print 'stdout:', out
stdout:
>>> print 'stderr:', err
stderr:Usage: wodim [options] track1...trackn
Options:
-version print version information and exit
dev=target SCSI target to use as CD/DVD-Recorder
gracetime=# set the grace time before starting to write to #.
...
Ответ 2
Если вы используете python 2.7 или новее, самый простой способ сделать это - использовать команду subprocess.check_output()
. Вот пример:
output = subprocess.check_output('ls')
Для перенаправления stderr вы можете использовать следующее:
output = subprocess.check_output('ls', stderr=subprocess.STDOUT)
В случае, если вы хотите передать параметры команде, вы можете либо использовать список, либо использовать вызов оболочки и использовать одну строку.
output = subprocess.check_output(['ls', '-a'])
output = subprocess.check_output('ls -a', shell=True)
Ответ 3
С a = subprocess.Popen("cdrecord --help",stdout = subprocess.PIPE)
вам нужно либо использовать список, либо использовать shell=True
;
Любой из них будет работать. Первый предпочтительнее.
a = subprocess.Popen(['cdrecord', '--help'], stdout=subprocess.PIPE)
a = subprocess.Popen('cdrecord --help', shell=True, stdout=subprocess.PIPE)
Кроме того, вместо Popen.stdout.read
/Popen.stderr.read
вы должны использовать .communicate()
(обратитесь к документации по подпроцессу для чего).
proc = subprocess.Popen(['cdrecord', '--help'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()