Эквивалент Bash Backticks в Python
Что эквивалентно обратным ссылкам, найденным в Ruby и Perl в Python? То есть в Ruby я могу сделать это:
foo = `cat /tmp/baz`
Как выглядит эквивалентное утверждение в Python? я пробовал os.system("cat /tmp/baz")
но это выводит результат в стандартный формат и возвращает мне код ошибки этой операции.
10 ответов
Самый гибкий способ - это использовать subprocess
модуль:
import subprocess
proc = subprocess.Popen(["cat", "/tmp/baz"], stdout=subprocess.PIPE)
(out, err) = proc.communicate()
print "program output:", out
Если вы хотите передать вызов через оболочку, например, чтобы получить расширение имени файла с *
, вы можете использовать shell=True
параметр. Если вы сделаете это, вы должны предоставить команду в виде строки, заключенной в кавычки /..., как если бы вы вводили ее в командной строке:
proc = subprocess.Popen('cat /tmp/ba* "s p a c e.txt"', shell=True, ...)
это правильно. Вы также можете использовать os.popen(), но там, где это возможно (Python 2.4+), подпроцесс обычно предпочтительнее.
Однако, в отличие от некоторых языков, которые поощряют это, обычно считается плохой формой создавать подпроцесс, где вы можете выполнять ту же работу внутри языка. Это медленнее, менее надежно и зависит от платформы. Ваш пример был бы лучше как:
foo= open('/tmp/baz').read()
ETA:
Баз это каталог, и я пытаюсь получить содержимое всех файлов в этом каталоге
? кошка в каталоге получает мне ошибку.
Если вы хотите список файлов:
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))
Начиная с Python 3.5 и далее рекомендуется использовать subprocess.run
, Чтобы получить то же поведение, которое вы описываете, вы должны использовать:
output = subprocess.run("ls", shell=True, stdout=subprocess.PIPE).stdout
Это вернет bytes
объект. Вы можете добавить .decode("ascii")
или же .decode("utf-8")
до конца, чтобы получить str
,
Самый простой способ - использовать пакет команд.
import commands
commands.getoutput("whoami")
Выход:
'Bganesan'
Я использую
(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 сделал это разумным.
Это не будет работать в 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`
Если вы используете subprocess.Popen, не забудьте указать bufsize. По умолчанию 0, что означает "небуферизованный", а не "выбрать разумное значение по умолчанию".
backtick
(`) оператор был удален в Python 3
, Это похоже на одиночную кавычку и трудно вводить на некоторых клавиатурах. Вместо backtick
, используйте эквивалентную встроенную функцию repr()
,