Как вы используете subprocess.check_output() в Python?
Я нашел документацию о subprocess.check_output(), но я не могу найти ее с аргументами, и документация не очень глубока. Я использую Python 3 (но пытаюсь запустить файл Python 2 через Python 3)
Я пытаюсь запустить эту команду:
python py2.py -i test.txt
-i - позиционный аргумент для argparse, test.txt - это то, что -i, py2.py - это файл для запуска
Я пробовал много (нерабочих) вариантов, в том числе:
py2output = subprocess.check_output([str('python py2.py '),'-i', 'test.txt'])
py2output = subprocess.check_output([str('python'),'py2.py','-i', test.txt'])
Ответы
Ответ 1
Правильный ответ (используя Python 2.7 и более поздние check_output()
, так как check_output()
был введен check_output()
):
py2output = subprocess.check_output(['python','py2.py','-i', 'test.txt'])
Чтобы продемонстрировать, вот мои две программы:
py2.py:
import sys
print sys.argv
py3.py:
import subprocess
py2output = subprocess.check_output(['python', 'py2.py', '-i', 'test.txt'])
print('py2 said:', py2output)
Запуск это:
$ python3 py3.py
py2 said: b"['py2.py', '-i', 'test.txt']\n"
Вот что не так с каждой из ваших версий:
py2output = subprocess.check_output([str('python py2.py '),'-i', 'test.txt'])
Во-первых, str('python py2.py')
- это то же самое, что и 'python py2.py'
вы берете str
и вызываете str
для преобразования его в str
. Это делает код сложнее для чтения, длиннее и даже медленнее, без каких-либо дополнительных преимуществ.
Более серьезно, python py2.py
не может быть одним аргументом, если вы на самом деле не пытаетесь запустить программу, скажем, /usr/bin/python\ py2.py
Который вы не; вы пытаетесь запустить, скажем, /usr/bin/python
с первым аргументом py2.py
Итак, вам нужно сделать их отдельными элементами в списке.
Ваша вторая версия исправляет это, но вам не хватает '
before test.txt'
. Это должно дать вам SyntaxError
, возможно, произносящую EOL while scanning string literal
.
Между тем, я не уверен, как вы нашли документацию, но не смогли найти никаких примеров с аргументами. Самый первый пример:
>>> subprocess.check_output(["echo", "Hello World!"])
b'Hello World!\n'
Это вызывает команду "echo"
с дополнительным аргументом "Hello World!"
,
Также:
-i - это позиционный аргумент для argparse, test.txt - это -i
Я уверен, что -i
не позиционный аргумент, а необязательный аргумент. В противном случае вторая половина предложения не имеет смысла.
Ответ 2
Добавляя к тому, который указан @abarnert
Лучше всего поймать исключение
import subprocess
try:
py2output = subprocess.check_output(['python', 'py2.py', '-i', 'test.txt'],stderr= subprocess.STDOUT)
#print('py2 said:', py2output)
print "here"
except subprocess.CalledProcessError as e:
print "Calledprocerr"
этот stderr = subprocess.STDOUT предназначен для того, чтобы вы не получили ошибку filenotfound в stderr, которая не может быть обычно поймана в filenotfoundexception, иначе вы в конечном итоге получите
python: can't open file 'py2.py': [Errno 2] No such file or directory
Наверное, лучшим решением для этого может быть проверка того, существуют ли файлы/сценарии, а затем запустить файл/script
Ответ 3
Начиная с Python 3.5, subprocess.run() рекомендуется вместо subprocess.check_output():
>>> subprocess.run(['cat','/tmp/text.txt'], stdout=subprocess.PIPE).stdout
b'First line\nSecond line\n'
Начиная с Python 3.7, вместо вышеуказанного вы можете использовать параметр capture_output=true
для захвата stdout и stderr:
>>> subprocess.run(['cat','/tmp/text.txt'], capture_output=True).stdout
b'First line\nSecond line\n'
Кроме того, вы можете использовать universal_newlines=True
или его эквивалент, так как Python 3.7 text=True
для работы с текстом вместо двоичного:
>>> stdout = subprocess.run(['cat', '/tmp/text.txt'], capture_output=True, text=True).stdout
>>> print(stdout)
First line
Second line
См. Subprocess.run() документация для получения дополнительной информации.
Ответ 4
Почему бы не мыслить нестандартно и использовать туалет, который должен быть быстрее
import subprocess
import re
def get_num_lines_in_file(filename):
num_lines = 0
op = subprocess.check_output(['wc','-l',filename])
m = re.search("^(\d+)",op)
if m:
num_lines = int(m.group(1))
return num_lines
f = "/etc/hosts"
print ("{} has {} lines".format(f,get_num_lines_in_file(f)))
Дает: /etc/hosts имеет 5 строк