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

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

foo = `cat /tmp/baz`

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


person Chris Bunch    schedule 11.09.2009    source источник
comment
stackoverflow.com/questions/2924310/   -  person jfs    schedule 19.09.2011


Ответы (11)


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

person sth    schedule 11.09.2009
comment
да, это единственный разумный способ, вы можете обернуть его в функцию, чтобы вы могли вызывать что-то вроде execute(command) - person Vinko Vrsalovic; 11.09.2009
comment
На самом деле это не работает для меня, так как в этом случае baz — это каталог, и я пытаюсь получить содержимое всех файлов в этом каталоге. (выполнение cat /tmp/baz/* работает в тиках, но не с помощью метода, описанного здесь) - person Chris Bunch; 11.09.2009
comment
re: * не работает; вместо этого используйте subprocess.Popen([cat, /tmp/baz], stdout=subprocess.PIPE, shell=True). Поскольку расширение шара (звезды) обрабатывается оболочкой, в этом случае модуль подпроцесса должен использовать расширение оболочки (предоставляется /bin/sh). - person Pasi Savolainen; 11.09.2009
comment
вы можете использовать заголовок subprocess.check_output() stackoverflow.com/questions/236737/ - person jfs; 04.02.2011
comment
Из docs.python.org/2/library/subprocess.html#popen -constructor : (с shell=True) Если args является последовательностью, первый элемент определяет командную строку, а любые дополнительные элементы будут рассматриваться как дополнительные аргументы для самой оболочки. Итак, если вы собираетесь использовать shell=True, то первым аргументом, вероятно, должна быть строка cat /tmp/baz. В качестве альтернативы, если вы хотите использовать последовательность в качестве первого аргумента, вы должны использовать shell=False - person onlynone; 11.01.2013
comment
Я думал, что вопрос касается эквивалента обратных кавычек в Python. Это больше похоже на эквивалент Python IO.popen() {} - person Jun-Dai Bates-Kobashigawa; 02.09.2014
comment
@gerrit: это не устарело. В документации рекомендуется subprocess.run() (не знаю, заслуженно ли это), если вам не нужна поддержка более ранних версий или если вам не нужна гибкость, обеспечиваемая Popen(). - person jfs; 28.03.2016

это правильно. Вы также можете использовать 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))
person bobince    schedule 11.09.2009
comment
Хотя это не был ответ на вопрос, это лучший ответ для обучения пользователей. - person noamtm; 28.02.2010
comment
Название вопроса - это то, что эквивалентно обратным кавычкам. Я предположил, что кошка была просто примером команды. Этот ответ не помогает в общем случае. - person Jason; 22.10.2017

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

cpe = subprocess.run("ls", shell=True, capture_output=True)

Это вернет объект subprocess.CompletedProcess. Вывод на stdout будет в cpe.stdout, вывод в stderr будет в cpe.stderr, оба из которых будут bytes объектами. Вы можете декодировать вывод, чтобы получить объект str, используя cpe.stdout.decode(), или получить, передав text=True в subprocess.run:

cpe = subprocess.run("ls", shell=True, capture_output=True, text=True)

В последнем случае cpe.stdout и cpe.stderr оба являются объектами str.

person gerrit    schedule 22.03.2016
comment
Начиная с Python 3.7, вы можете использовать параметр text=True, чтобы вернуть строку вместо байтов. - person bwv549; 13.10.2020

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

import commands

commands.getoutput("whoami")

Вывод:

'бганесан'

person Balachander Ganesan    schedule 28.07.2014
comment
Очень просто, но модуль теперь устарел. - person Gringo Suave; 14.09.2015

я использую

(6:0)$ python --версия 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. Посмотрев строку документа для подпроцесса, я заменил

[ "прог", "аргумент"]

с участием

"прог аргумент"

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

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


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

person funkyj    schedule 11.03.2011

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

person George    schedule 13.04.2010

Это не будет работать в 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`
person ThorSummoner    schedule 19.04.2015
comment
Также вам, вероятно, не следует этого делать * - person ThorSummoner; 02.10.2015

repr()

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

person Pedro Lobito    schedule 09.04.2019
comment
Это не эквивалент обратных кавычек bash. - person gerrit; 13.10.2020

person    schedule
comment
@mckenzm Вопрос о захвате вывода внешнего процесса. Захват вывода функции Python — это совсем другой вопрос. - person John Kugelman; 02.01.2015
comment
Удивительно лаконичный и действительно эквивалентный Ruby `...` (захват stdout, передача stderr) - с одним исключением: Ruby позволяет определить код завершения процесса через$?по факту; в Python, насколько я могу судить, для этого вам придется использовать функции модуля subprocess. - person mklement0; 10.04.2019

person    schedule
comment
Сейчас это самый простой способ. subprocess.check_output был добавлен в Python 2.7, выпущенном в июле 2010 года, после того, как были даны другие всплывающие ответы. - person Robert Fleming; 18.04.2013

person    schedule
comment
Это эквивалент обратных кавычек Ruby, но если ваша проблема состоит в том, чтобы вывести список содержимого каталога, то это не лучший способ сделать это. - person awatts; 11.09.2009