Запуск команды оболочки и получение вывода
Я хочу написать функцию, которая будет выполнять команду оболочки и возвращать ее вывод в виде строки, независимо от того, является ли это ошибкой или сообщением об успехе. Я просто хочу получить тот же результат, который я получил бы с командной строкой.
Каким был бы пример кода, который сделал бы такую вещь?
Например:
def run_command(cmd):
# ??????
print run_command('mysqladmin create test -uroot -pmysqladmin12')
# Should output something like:
# mysqladmin: CREATE DATABASE failed; error: 'Can't create database 'test'; database exists'
28 ответов
Ответ на этот вопрос зависит от версии Python, которую вы используете. Самый простой подход заключается в использовании subprocess.check_output
функция:
>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
check_output
запускает одну программу, которая принимает только аргументы в качестве входных данных. 1 Возвращает результат в точности как напечатано stdout
, Если вам нужно написать вход stdin
Пропустите к run
или же Popen
разделы. Если вы хотите выполнить сложные команды оболочки, см. Примечание shell=True
в конце этого ответа.
check_output
Функция работает практически на всех версиях Python, все еще широко используемых (2.7+). 2 Но для более поздних версий это уже не рекомендуемый подход.
Современные версии Python (3.5 или выше): run
Если вы используете Python 3.5 или выше и не нуждаетесь в обратной совместимости, новый run
функция рекомендуется. Он предоставляет очень общий высокоуровневый API для subprocess
модуль. Чтобы захватить вывод программы, передайте subprocess.PIPE
флаг к stdout
Ключевой аргумент. Затем получите доступ к stdout
атрибут возвращаемого CompletedProcess
объект:
>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
Возвращаемое значение bytes
объект, поэтому, если вы хотите правильную строку, вам нужно decode
Это. Предполагая, что вызываемый процесс возвращает строку в кодировке UTF-8:
>>> result.stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
Все это можно сжать до одной строки:
>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
Если вы хотите передать ввод процессу stdin
пройди bytes
возражать против input
Ключевой аргумент:
>>> cmd = ['awk', 'length($0) > 5']
>>> input = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=input)
>>> result.stdout.decode('utf-8')
'foofoo\n'
Вы можете фиксировать ошибки, передавая stderr=subprocess.PIPE
(захватить в result.stderr
) или же stderr=subprocess.STDOUT
(захватить в result.stdout
наряду с регулярным выходом). Когда безопасность не имеет значения, вы также можете запускать более сложные команды оболочки, передавая shell=True
как описано в примечаниях ниже.
Это добавляет немного сложности по сравнению со старым способом ведения дел. Но я думаю, что это того стоит: теперь вы можете делать практически все, что вам нужно сделать с run
функционировать в одиночку.
Более старые версии Python (2.7-3.4): check_output
Если вы используете более старую версию Python или вам нужна скромная обратная совместимость, вы можете использовать check_output
функционировать как кратко описано выше. Он был доступен с Python 2.7.
subprocess.check_output(*popenargs, **kwargs)
Он принимает те же аргументы, что и Popen
(см. ниже) и возвращает строку, содержащую выходные данные программы. В начале этого ответа приведен более подробный пример использования.
Вы можете пройти stderr=subprocess.STDOUT
чтобы убедиться, что сообщения об ошибках включены в возвращаемый вывод, но не проходят stderr=subprocess.PIPE
в check_output
, Это может вызвать тупики. Когда безопасность не имеет значения, вы также можете запускать более сложные команды оболочки, передавая shell=True
как описано в примечаниях ниже.
Если вам нужно из трубы stderr
или передать ввод процессу, check_output
не будет до задачи. Увидеть Popen
примеры ниже в этом случае.
Сложные приложения и устаревшие версии Python (2.6 и ниже): Popen
Если вам нужна глубокая обратная совместимость, или если вам нужна более сложная функциональность, чем check_output
обеспечивает, вам придется работать напрямую с Popen
объекты, которые инкапсулируют низкоуровневый API для подпроцессов.
Popen
Конструктор принимает либо одну команду без аргументов, либо список, содержащий команду в качестве первого элемента, за которым следует любое количество аргументов, каждый из которых является отдельным элементом в списке. shlex.split
может помочь разобрать строки в соответственно отформатированных списках. Popen
объекты также принимают множество различных аргументов для управления процессами ввода-вывода и низкоуровневой конфигурации.
Чтобы отправить ввод и захватить вывод, communicate
почти всегда предпочтительный метод. Как в:
output = subprocess.Popen(["mycmd", "myarg"],
stdout=subprocess.PIPE).communicate()[0]
Или же
>>> import subprocess
>>> p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE,
... stderr=subprocess.PIPE)
>>> out, err = p.communicate()
>>> print out
.
..
foo
Если вы установите stdin=PIPE
, communicate
также позволяет передавать данные в процесс через stdin
:
>>> cmd = ['awk', 'length($0) > 5']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
... stderr=subprocess.PIPE,
... stdin=subprocess.PIPE)
>>> out, err = p.communicate('foo\nfoofoo\n')
>>> print out
foofoo
Обратите внимание на ответ Аарона Холла, который указывает, что в некоторых системах вам может потребоваться установить stdout
, stderr
, а также stdin
все для PIPE
(или же DEVNULL
) получить communicate
работать на всех.
В некоторых редких случаях вам может потребоваться сложный захват результатов в реальном времени. Ответ Вартека предлагает путь вперед, но методы, кроме communicate
склонны к тупикам, если не используются осторожно.
Как и во всех вышеперечисленных функциях, когда безопасность не имеет значения, вы можете запускать более сложные команды оболочки, передавая shell=True
,
Заметки
1. Запуск команд оболочки: shell=True
аргумент
Обычно каждый звонок run
, check_output
, или Popen
Конструктор выполняет одну программу. Это означает, что нет причудливых трубок в стиле Bash. Если вы хотите запускать сложные команды оболочки, вы можете передать shell=True
, которые поддерживают все три функции.
Однако при этом возникают проблемы с безопасностью. Если вы делаете что-то большее, чем простой сценарий, вам лучше будет вызывать каждый процесс отдельно и передавать выходные данные каждого из них в качестве входных данных следующему через
run(cmd, [stdout=etc...], input=other_output)
Или же
Popen(cmd, [stdout=etc...]).communicate(other_output)
Искушение напрямую соединить трубы сильно; сопротивляться этому. В противном случае вы, скорее всего, увидите тупики или будете делать такие хакерские вещи.
2. Юникод соображения
check_output
возвращает строку в Python 2, но bytes
объект в Python 3. Стоит потратить немного времени на изучение юникода, если вы еще этого не сделали.
Это намного проще, но работает только на Unix (включая Cygwin).
import commands
print commands.getstatusoutput('wc -l file')
возвращает кортеж с (return_value, output)
Это работает только в python2.7
: это не доступно на python3
, Для решения, которое работает в обоих, используйте subprocess
модуль вместо:
import subprocess
output=subprocess.Popen(["date"],stdout=PIPE)
response=output.communicate()
print response
У меня была такая же проблема, но я понял очень простой способ сделать это, следуйте этому
import subprocess
output = subprocess.getoutput("ls -l")
print(output)
Надеюсь, это поможет
Примечание: это решение относится к Python3 как subprocess.getoutput()
не работает в python2
Что-то вроде того:
def runProcess(exe):
p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while(True):
retcode = p.poll() #returns None while subprocess is running
line = p.stdout.readline()
yield line
if(retcode is not None):
break
Обратите внимание, что я перенаправляю stderr в stdout, это может быть не совсем то, что вы хотите, но я также хочу сообщения об ошибках.
Эта функция выдает построчно по мере их поступления (обычно вам нужно подождать, пока подпроцесс завершит работу, чтобы получить выходные данные в целом).
Для вашего случая использование будет:
for line in runProcess('mysqladmin create test -uroot -pmysqladmin12'.split()):
print line,
Это сложное, но очень простое решение, которое работает во многих ситуациях:
import os
os.system('sample_cmd > tmp')
print open('tmp', 'r').read()
Временный файл (здесь tmp) создается с выводом команды, и вы можете прочитать из него желаемый вывод.
Дополнительное примечание к комментариям: Вы можете удалить файл tmp в случае разовой работы. Если вам нужно сделать это несколько раз, нет необходимости удалять TMP.
os.remove('tmp')
Ответ Вартека не читает все строки, поэтому я сделал версию, которая сделала:
def run_command(command):
p = subprocess.Popen(command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
return iter(p.stdout.readline, b'')
Использование такое же, как принятый ответ:
command = 'mysqladmin create test -uroot -pmysqladmin12'.split()
for line in run_command(command):
print(line)
Вы можете использовать следующие команды для запуска любой команды оболочки. Я использовал их на Ubuntu.
import os
os.popen('your command here').read()
В Python 3.7+ используйтеsubprocess.run
и пройти
capture_output=True
:
import subprocess
result = subprocess.run(['echo', 'hello', 'world'], capture_output=True)
print(repr(result.stdout))
Это вернет байты:
b'hello world\n'
Если вы хотите преобразовать байты в строку, добавьте:
result = subprocess.run(['echo', 'hello', 'world'], capture_output=True, text=True)
print(repr(result.stdout))
Это будет читать байты с использованием кодировки по умолчанию:
'hello world\n'
Если вам нужно вручную указать другую кодировку, используйте
encoding="your encoding"
вместо
text=True
:
result = subprocess.run(['echo', 'hello', 'world'], capture_output=True, encoding="utf8")
print(repr(result.stdout))
В Python 3.5:
import subprocess
output = subprocess.run("ls -l", shell=True, stdout=subprocess.PIPE,
universal_newlines=True)
print(output.stdout)
У меня была немного другая разновидность той же проблемы со следующими требованиями:
- Захват и возврат сообщений STDOUT по мере их накопления в буфере STDOUT (то есть в режиме реального времени).
- @vartec решила эту проблему с помощью генераторов и "yield"
ключевое слово выше
- @vartec решила эту проблему с помощью генераторов и "yield"
- Вывести все строки STDOUT (даже если процесс завершается до того, как буфер STDOUT может быть полностью прочитан)
- Не тратьте циклы процессора, опрашивая процесс на высокой частоте
- Проверьте код возврата подпроцесса
- Выведите STDERR (отдельно от STDOUT), если мы получим ненулевой код возврата ошибки.
Я объединил и подправил предыдущие ответы, чтобы придумать следующее:
import subprocess
from time import sleep
def run_command(command):
p = subprocess.Popen(command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True)
# Read stdout from subprocess until the buffer is empty !
for line in iter(p.stdout.readline, b''):
if line: # Don't print blank lines
yield line
# This ensures the process has completed, AND sets the 'returncode' attr
while p.poll() is None:
sleep(.1) #Don't waste CPU-cycles
# Empty STDERR buffer
err = p.stderr.read()
if p.returncode != 0:
# The run_command() function is responsible for logging STDERR
print("Error: " + str(err))
Этот код будет выполнен так же, как и предыдущие ответы:
for line in run_command(cmd):
print(line)
Ваш пробег может меняться, я попытался @senderle прокрутить решение Vartec в Windows на Python 2.6.5, но я получал ошибки, и другие решения не работали. Моя ошибка была: WindowsError: [Error 6] The handle is invalid
,
Я обнаружил, что мне нужно было назначить PIPE для каждого дескриптора, чтобы он возвращал ожидаемый результат - мне помогло следующее.
import subprocess
def run_command(cmd):
"""given shell command, returns communication tuple of stdout and stderr"""
return subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE).communicate()
и звони так, ([0]
получает первый элемент кортежа, stdout
):
run_command('tracert 11.1.0.1')[0]
Узнав больше, я считаю, что мне нужны эти аргументы конвейера, потому что я работаю над пользовательской системой, которая использует разные дескрипторы, поэтому мне пришлось напрямую контролировать все std.
Чтобы остановить всплывающие окна консоли (с Windows), сделайте это:
def run_command(cmd):
"""given shell command, returns communication tuple of stdout and stderr"""
# instantiate a startupinfo obj:
startupinfo = subprocess.STARTUPINFO()
# set the use show window flag, might make conditional on being in Windows:
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
# pass as the startupinfo keyword argument:
return subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
startupinfo=startupinfo).communicate()
run_command('tracert 11.1.0.1')
Современное решение Python (>= 3.1):
res = subprocess.check_output(lcmd, stderr=subprocess.STDOUT)
Разделение начальной команды для subprocess
может быть сложно и громоздко.
использование shlex.split
чтобы помочь себе.
Пример команды
git log -n 5 --since "5 years ago" --until "2 year ago"
Код
from subprocess import check_output
from shlex import split
res = check_output(split('git log -n 5 --since "5 years ago" --until "2 year ago"'))
print(res)
>>> b'commit 7696ab087a163e084d6870bb4e5e4d4198bdc61a\nAuthor: Artur Barseghyan...'
По какой-то причине этот работает на Python 2.7, и вам нужно только импортировать os!
import os
def bash(command):
output = os.popen(command).read()
return output
print_me = bash('ls -l')
print print_me
Вот решение, работающее, если вы хотите распечатать вывод во время работы процесса или нет.
Я также добавил текущий рабочий каталог, он мне пригодился не раз.
Надеясь, что решение кому-то поможет:).
import subprocess
def run_command(cmd_and_args, print_constantly=False, cwd=None):
"""Runs a system command.
:param cmd_and_args: the command to run with or without a Pipe (|).
:param print_constantly: If True then the output is logged in continuous until the command ended.
:param cwd: the current working directory (the directory from which you will like to execute the command)
:return: - a tuple containing the return code, the stdout and the stderr of the command
"""
output = []
process = subprocess.Popen(cmd_and_args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd)
while True:
next_line = process.stdout.readline()
if next_line:
output.append(str(next_line))
if print_constantly:
print(next_line)
elif not process.poll():
break
error = process.communicate()[1]
return process.returncode, '\n'.join(output), error
Если вам нужно запустить команду оболочки для нескольких файлов, это помогло мне.
import os
import subprocess
# Define a function for running commands and capturing stdout line by line
# (Modified from Vartec's solution because it wasn't printing all lines)
def runProcess(exe):
p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
return iter(p.stdout.readline, b'')
# Get all filenames in working directory
for filename in os.listdir('./'):
# This command will be run on each file
cmd = 'nm ' + filename
# Run the command and capture the output line by line.
for line in runProcess(cmd.split()):
# Eliminate leading and trailing whitespace
line.strip()
# Split the output
output = line.split()
# Filter the output and print relevant lines
if len(output) > 2:
if ((output[2] == 'set_program_name')):
print filename
print line
Изменить: Только что увидел решение Макса Перссона с предложением JF Себастьяна. Ушел вперед и включил это.
Согласно @senderle, если вы используете Python3.6, как я:
def sh(cmd, input=""):
rst = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, input=input.encode("utf-8"))
assert rst.returncode == 0, rst.stderr.decode("utf-8")
return rst.stdout.decode("utf-8")
sh("ls -a")
Будет действовать так же, как вы запускаете команду в Bash
Ключевым моментом является использование функцииsubprocess.check_output
Например, следующая функция захватывает stdout и stderr процесса и возвращает их, а также информацию о том, был ли вызов успешным. Он совместим с Python 2 и 3:
from subprocess import check_output, CalledProcessError, STDOUT
def system_call(command):
"""
params:
command: list of strings, ex. `["ls", "-l"]`
returns: output, success
"""
try:
output = check_output(command, stderr=STDOUT).decode()
success = True
except CalledProcessError as e:
output = e.output.decode()
success = False
return output, success
output, success = system_call(["ls", "-l"])
Если вы хотите передавать команды в виде строк, а не массивов, используйте эту версию:
from subprocess import check_output, CalledProcessError, STDOUT
import shlex
def system_call(command):
"""
params:
command: string, ex. `"ls -l"`
returns: output, success
"""
command = shlex.split(command)
try:
output = check_output(command, stderr=STDOUT).decode()
success = True
except CalledProcessError as e:
output = e.output.decode()
success = False
return output, success
output, success = system_call("ls -l")
Улучшение для лучшего ведения журнала.
Для лучшего вывода вы можете использовать итератор. Снизу мы поправляемся
from subprocess import Popen, getstatusoutput, PIPE
def shell_command(cmd):
result = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
output = iter(result.stdout.readline, b'')
error = iter(result.stderr.readline, b'')
print("##### OutPut ###")
for line in output:
print(line.decode("utf-8"))
print("###### Error ########")
for line in error:
print(error.decode("utf-8")) # Convert bytes to str
status, terminal_output = run_command(cmd)
print(terminal_output)
shell_command("ls") # this will display all the files & folders in directory
Другой метод с использованием getstatusoutput (легко понять)
from subprocess import Popen, getstatusoutput, PIPE
status_Code, output = getstausoutput(command)
print(output) # this will give the terminal output
# status_code, output = getstatusoutput("ls") # this will print the all files & folder available in the directory
Я хотел бы предложить simppl как вариант для рассмотрения. Это модуль, доступный через pypi:
pip install simppl
и работал на python3.
simppl
позволяет пользователю запускать команды оболочки и читать вывод с экрана.
Разработчики предлагают три варианта использования:
- Самое простое использование будет выглядеть так:
from simppl.simple_pipeline import SimplePipeline sp = SimplePipeline(start=0, end=100): sp.print_and_run('<YOUR_FIRST_OS_COMMAND>') sp.print_and_run('<YOUR_SECOND_OS_COMMAND>') ```
- Для одновременного запуска нескольких команд используйте:
commands = ['<YOUR_FIRST_OS_COMMAND>', '<YOUR_SECOND_OS_COMMAND>'] max_number_of_processes = 4 sp.run_parallel(commands, max_number_of_processes) ```
- Наконец, если ваш проект использует модуль cli, вы можете напрямую запустить другой command_line_tool как часть конвейера. Другой инструмент будет запущен из того же процесса, но он будет отображаться в журналах как другая команда в конвейере. Это обеспечивает более плавную отладку и рефакторинг инструментов, вызывающих другие инструменты.
from example_module import example_tool sp.print_and_run_clt(example_tool.run, ['first_number', 'second_nmber'], {'-key1': 'val1', '-key2': 'val2'}, {'--flag'}) ```
Обратите внимание, что печать в STDOUT/STDERR осуществляется через python
logging
модуль.
Вот полный код, показывающий, как работает simppl:
import logging
from logging.config import dictConfig
logging_config = dict(
version = 1,
formatters = {
'f': {'format':
'%(asctime)s %(name)-12s %(levelname)-8s %(message)s'}
},
handlers = {
'h': {'class': 'logging.StreamHandler',
'formatter': 'f',
'level': logging.DEBUG}
},
root = {
'handlers': ['h'],
'level': logging.DEBUG,
},
)
dictConfig(logging_config)
from simppl.simple_pipeline import SimplePipeline
sp = SimplePipeline(0, 100)
sp.print_and_run('ls')
Если вы используете subprocess
Модуль Python, вы можете обрабатывать STDOUT, STDERR и код возврата команды отдельно. Вы можете увидеть пример полной реализации вызывающей команды. Конечно, вы можете расширить его с try..except
если ты хочешь.
Приведенная ниже функция возвращает STDOUT, STDERR и код возврата, чтобы вы могли обрабатывать их в другом скрипте.
import subprocess
def command_caller(command=None)
sp = subprocess.Popen(command, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=False)
out, err = sp.communicate()
if sp.returncode:
print(
"Return code: %(ret_code)s Error message: %(err_msg)s"
% {"ret_code": sp.returncode, "err_msg": err}
)
return sp.returncode, out, err
Вот простое и гибкое решение, которое работает с различными версиями ОС, а также с Python 2 и 3, используя IPython в режиме оболочки:
from IPython.terminal.embed import InteractiveShellEmbed
my_shell = InteractiveShellEmbed()
result = my_shell.getoutput("echo hello world")
print(result)
Out: ['hello world']
У него есть несколько преимуществ
- Для этого требуется только установка IPython, поэтому вам не нужно беспокоиться о вашей конкретной версии Python или ОС при его использовании, он поставляется с Jupyter, который имеет широкий спектр поддержки.
- По умолчанию требуется простая строка, поэтому нет необходимости использовать аргумент режима оболочки или разделение строк, что делает его немного чище IMO
- Это также упрощает замену переменных или даже целых команд Python в самой строке.
Демонстрировать:
var = "hello world "
result = my_shell.getoutput("echo {var*2}")
print(result)
Out: ['hello world hello world']
Просто хотел дать вам дополнительную возможность, особенно если у вас уже установлен Jupyter
Естественно, если вы используете настоящий блокнот Jupyter, а не скрипт .py, вы также всегда можете сделать:
result = !echo hello world
print(result)
Чтобы добиться того же.
Это код, который я использую для поддержки многопоточности в ячейке ноутбука Jupyter и печати выходных данных оболочки в режиме реального времени. Он используетbufsize
иstderr
.
from subprocess import Popen, PIPE, STDOUT
def verbosecmd(command):
with Popen(
command, stdout=PIPE, shell=True, stderr=STDOUT, bufsize=0, close_fds=True
) as process:
for line in iter(process.stdout.readline, b""):
print(line.rstrip().decode("utf-8"))
1-строчный (для одержимых)
def cmd(x): from subprocess import check_output as c; return c(x, shell=True, text=True) # noqa
Применение
print(cmd('ls -la')) #linux
print(cmd('ipconfig')) #windows
Комментарии
- не беспокойтесь о том, что подпроцесс импортируется каждый раз, последующие вызовы просто индексируются как переменная
- это не соответствует стандарту форматирования pep8 и теряет одну строку при сохранении, если какой-либо форматтер настроен в vscode, вы можете игнорировать использование
--ignore=E702,E704,E501
добавив в настройки или добавив# noqa
в конце (я уже добавил) ссылку на этот ответ - Также возникают ошибки, а не передаются молча.
Если вы хотите захватить как stdout, так и stderr и отобразить их так, как они будут выглядеть, когда команда оболочки выполняется в интерактивном терминале, и вам нужно знать статус возврата команды, вы можете сделать следующий трюк.
import time, os
cmd_str = "ls -d /bin/nonsense"
tmpfile= "/tmp/results." + str(os.getpid()) + "." + str(time.time())
status = os.system( cmd_str + " > " + tmpfile +" 2>&1")
with open(tmpfile, 'r') as f:
print (f.read())
os.remove(tmpfile)
print("status=" + str(status))
Примечание. Файл tmpfile уникален и удаляется сразу после использования. Для анализа cmd_str используется оболочка, поэтому не используйте этот метод для произвольных строк, поскольку это небезопасно.
Просто написал небольшой скрипт на bash, чтобы сделать это с помощью curl
https://gist.github.com/harish2704/bfb8abece94893c53ce344548ead8ba5
#!/usr/bin/env bash
# Usage: gdrive_dl.sh <url>
urlBase='https://drive.google.com'
fCookie=tmpcookies
curl="curl -L -b $fCookie -c $fCookie"
confirm(){
$curl "$1" | grep jfk-button-action | sed -e 's/.*jfk-button-action" href="\(\S*\)".*/\1/' -e 's/\&/\&/g'
}
$curl -O -J "${urlBase}$(confirm $1)"
Вывод может быть перенаправлен в текстовый файл, а затем прочитать его обратно.
import subprocess
import os
import tempfile
def execute_to_file(command):
"""
This function execute the command
and pass its output to a tempfile then read it back
It is usefull for process that deploy child process
"""
temp_file = tempfile.NamedTemporaryFile(delete=False)
temp_file.close()
path = temp_file.name
command = command + " > " + path
proc = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
if proc.stderr:
# if command failed return
os.unlink(path)
return
with open(path, 'r') as f:
data = f.read()
os.unlink(path)
return data
if __name__ == "__main__":
path = "Somepath"
command = 'ecls.exe /files ' + path
print(execute(command))
Например, execute('ls -ahl') различает три / четыре возможных возврата и платформы ОС:
- не выводится, но работает успешно
- вывести пустую строку, запустить успешно
- бежать не удалось
- вывести что-нибудь, запустить успешно
функция ниже
def execute(cmd, output=True, DEBUG_MODE=False):
"""Executes a bash command.
(cmd, output=True)
output: whether print shell output to screen, only affects screen display, does not affect returned values
return: ...regardless of output=True/False...
returns shell output as a list with each elment is a line of string (whitespace stripped both sides) from output
could be
[], ie, len()=0 --> no output;
[''] --> output empty line;
None --> error occured, see below
if error ocurs, returns None (ie, is None), print out the error message to screen
"""
if not DEBUG_MODE:
print "Command: " + cmd
# https://stackru.com/a/40139101/2292993
def _execute_cmd(cmd):
if os.name == 'nt' or platform.system() == 'Windows':
# set stdin, out, err all to PIPE to get results (other than None) after run the Popen() instance
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
else:
# Use bash; the default is sh
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, executable="/bin/bash")
# the Popen() instance starts running once instantiated (??)
# additionally, communicate(), or poll() and wait process to terminate
# communicate() accepts optional input as stdin to the pipe (requires setting stdin=subprocess.PIPE above), return out, err as tuple
# if communicate(), the results are buffered in memory
# Read stdout from subprocess until the buffer is empty !
# if error occurs, the stdout is '', which means the below loop is essentially skipped
# A prefix of 'b' or 'B' is ignored in Python 2;
# it indicates that the literal should become a bytes literal in Python 3
# (e.g. when code is automatically converted with 2to3).
# return iter(p.stdout.readline, b'')
for line in iter(p.stdout.readline, b''):
# # Windows has \r\n, Unix has \n, Old mac has \r
# if line not in ['','\n','\r','\r\n']: # Don't print blank lines
yield line
while p.poll() is None:
sleep(.1) #Don't waste CPU-cycles
# Empty STDERR buffer
err = p.stderr.read()
if p.returncode != 0:
# responsible for logging STDERR
print("Error: " + str(err))
yield None
out = []
for line in _execute_cmd(cmd):
# error did not occur earlier
if line is not None:
# trailing comma to avoid a newline (by print itself) being printed
if output: print line,
out.append(line.strip())
else:
# error occured earlier
out = None
return out
else:
print "Simulation! The command is " + cmd
print ""