Эквивалент Bash Backticks в Python - PullRequest
       19

Эквивалент Bash Backticks в Python

77 голосов
/ 11 сентября 2009

Что эквивалентно обратным ссылкам, найденным в Ruby и Perl в Python? То есть в Ruby я могу сделать это:

foo = `cat /tmp/baz`

Как выглядит эквивалентное утверждение в Python? Я пробовал os.system("cat /tmp/baz"), но это выводит результат в стандартный формат и возвращает мне код ошибки этой операции.

Ответы [ 11 ]

90 голосов
/ 11 сентября 2009
output = os.popen('cat /tmp/baz').read()
81 голосов
/ 11 сентября 2009

Самый гибкий способ - использовать модуль subprocess:

import subprocess

out = subprocess.run(["cat", "/tmp/baz"], capture_output=True)
print("program output:", out)

capture_output была введена в Python 3.7, для более старых версий вместо нее можно использовать специальную функцию check_output():

out = subprocess.check_output(["cat", "/tmp/baz"])

Вы также можете вручную создать объект подпроцесса, если вам нужен детальный контроль:

proc = subprocess.Popen(["cat", "/tmp/baz"], stdout=subprocess.PIPE)
(out, err) = proc.communicate()

Все эти функции поддерживают параметры ключевых слов для настройки способа выполнения подпроцесса. Например, вы можете использовать shell=True для выполнения программы через оболочку, если вам нужны такие вещи, как расширения имен файлов *, но это идет с ограничениями .

26 голосов
/ 11 сентября 2009

справа - 100 *. Вы также можете использовать os.popen (), но там, где это возможно (Python 2.4+), подпроцесс обычно предпочтительнее.

Однако, в отличие от некоторых языков, которые его поощряют, обычно считается плохой формой создавать подпроцесс, в котором вы можете выполнять ту же работу внутри языка. Это медленнее, менее надежно и зависит от платформы. Ваш пример будет лучше как:

foo= open('/tmp/baz').read()

ет:

baz - это каталог, и я пытаюсь получить содержимое всех файлов в этом каталоге

? кошка в каталоге получает мне ошибку.

Если вы хотите список файлов:

import os
foo= os.listdir('/tmp/baz')

Если вы хотите содержимое всех файлов в каталоге, что-то вроде:

contents= []
for leaf in os.listdir('/tmp/baz'):
    path= os.path.join('/tmp/baz', leaf)
    if os.path.isfile(path):
        contents.append(open(path, 'rb').read())
foo= ''.join(contents)

или, если вы можете быть уверены, что там нет каталогов, вы можете поместить его в одну строку:

path= '/tmp/baz'
foo= ''.join(open(os.path.join(path, child), 'rb').read() for child in os.listdir(path))
15 голосов
/ 19 сентября 2011
foo = subprocess.check_output(["cat", "/tmp/baz"])
9 голосов
/ 22 марта 2016

Начиная с версии Python 3.5, рекомендуется использовать subprocess.run. Чтобы получить то же поведение, которое вы описываете, вы должны использовать:

output = subprocess.run("ls", shell=True, stdout=subprocess.PIPE).stdout

Это вернет объект bytes. Вы можете добавить .decode("ascii") или .decode("utf-8") до конца, чтобы получить str.

6 голосов
/ 28 июля 2014

Самый простой способ - использовать пакет команд.

import commands

commands.getoutput("whoami")

Выход:

'bganesan'

3 голосов
/ 11 сентября 2009
import os
foo = os.popen('cat /tmp/baz', 'r').read()
2 голосов
/ 12 марта 2011

Я использую

(6: 0) $ python --version Python 2.7.1

Один из приведенных выше примеров:

import subprocess
proc = subprocess.Popen(["cat", "/tmp/baz"], stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
print "program output:", out

Для меня это не удалось получить доступ к каталогу / tmp. После просмотра строки документа для подпроцесса я заменил

["prog", "arg"]

с

"prog arg"

и получил желаемое поведение расширения оболочки (а-ля Perl `prog arg`)

print subprocess.Popen ("ls -ld / tmp / v *", stdout = subprocess.PIPE, shell = True) .communicate () [0]


Я перестал использовать python некоторое время назад, потому что был раздражен трудностью сделать эквивалент perl `cmd ...`. Я рад, что Python сделал это разумным.

1 голос
/ 19 апреля 2015

Это не будет работать в python3, но в python2 вы можете расширить str с помощью пользовательского __repr__ метода, который вызывает вашу команду оболочки и возвращает ее так:

#!/usr/bin/env python

import os

class Command(str):
    """Call system commands"""

    def __repr__(cmd):
        return os.popen(cmd).read()

Который вы можете использовать как

#!/usr/bin/env python
from command import Command

who_i_am = `Command('whoami')`

# Or predeclare your shell command strings
whoami = Command('whoami')
who_i_am = `whoami`
1 голос
/ 13 апреля 2010

Если вы используете subprocess.Popen, не забудьте указать bufsize. По умолчанию 0, что означает «небуферизованный», а не «выбрать разумное значение по умолчанию».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...