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

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

foo = `cat /tmp/baz`

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

Ответ 1

output = os.popen('cat /tmp/baz').read()

Ответ 2

Наиболее гибкий способ - использовать модуль 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 для выполнения программы через оболочку, если вам нужны такие вещи, как расширения имен файлов *, но это имеет ограничения.

Ответ 3

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

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

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

ет:

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

? cat в каталоге вызывает у меня ошибку.

Если вам нужен список файлов:

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))

Ответ 4

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

Ответ 5

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

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

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

Ответ 6

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

import commands

commands.getoutput("whoami")

Вывод:

'bganesan'

Ответ 7

import os
foo = os.popen('cat /tmp/baz', 'r').read()

Ответ 8

Я использую

(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"

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

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


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

Ответ 9

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

Ответ 10

Это не будет работать в 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`

Ответ 11

repr()

Оператор backtick (') был удален в Python 3. Это похоже на одиночную кавычку и трудно вводить на некоторых клавиатурах. Вместо backtick используйте эквивалентную встроенную функцию repr().