Запуск команды оболочки и получение вывода

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

Каким был бы пример кода, который сделал бы такую ​​вещь?

Например:

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)

У меня была немного другая разновидность той же проблемы со следующими требованиями:

  1. Захват и возврат сообщений STDOUT по мере их накопления в буфере STDOUT (то есть в режиме реального времени).
    • @vartec решила эту проблему с помощью генераторов и "yield"
      ключевое слово выше
  2. Вывести все строки STDOUT (даже если процесс завершается до того, как буфер STDOUT может быть полностью прочитан)
  3. Не тратьте циклы процессора, опрашивая процесс на высокой частоте
  4. Проверьте код возврата подпроцесса
  5. Выведите 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 позволяет пользователю запускать команды оболочки и читать вывод с экрана.

Разработчики предлагают три варианта использования:

  1. Самое простое использование будет выглядеть так:
    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>') ```

  1. Для одновременного запуска нескольких команд используйте:
    commands = ['<YOUR_FIRST_OS_COMMAND>', '<YOUR_SECOND_OS_COMMAND>']
    max_number_of_processes = 4
    sp.run_parallel(commands, max_number_of_processes) ```

  1. Наконец, если ваш проект использует модуль 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']

У него есть несколько преимуществ

  1. Для этого требуется только установка IPython, поэтому вам не нужно беспокоиться о вашей конкретной версии Python или ОС при его использовании, он поставляется с Jupyter, который имеет широкий спектр поддержки.
  2. По умолчанию требуется простая строка, поэтому нет необходимости использовать аргумент режима оболочки или разделение строк, что делает его немного чище IMO
  3. Это также упрощает замену переменных или даже целых команд 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/\&amp;/\&/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') различает три / четыре возможных возврата и платформы ОС:

  1. не выводится, но работает успешно
  2. вывести пустую строку, запустить успешно
  3. бежать не удалось
  4. вывести что-нибудь, запустить успешно

функция ниже

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 ""
Другие вопросы по тегам