Запуск команди оболонки та фіксація виводу


906

Я хочу написати функцію, яка виконає команду shell і поверне її вихід у вигляді рядка , незалежно від того, чи це повідомлення про помилку чи успіх. Я просто хочу отримати той самий результат, який я отримав би з командного рядка.

Що б було прикладом коду, який би робив таке?

Наприклад:

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'

Відповіді:


1137

Відповідь на це питання залежить від версії 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(див. Нижче), і повертає рядок, що містить вихід програми. На початку цієї відповіді є більш детальний приклад використання. У Python 3.5 та новіших версіях check_outputеквівалентно виконанню runз check=Trueта stdout=PIPEта поверненню лише stdoutатрибута.

Ви можете перейти stderr=subprocess.STDOUTдо того , щоб повідомлення про помилки включені в повернутому виході - але в деяких версіях Python переходу stderr=subprocess.PIPEдо check_outputможе привести до тупикам . Якщо безпека не викликає занепокоєнь, ви також можете запускати більш складні команди оболонки, передаючи, shell=Trueяк описано в примітках нижче.

Якщо вам потрібно stderrпередавати або передавати вхід в процес, завдання check_outputне буде вирішено. Дивіться Popenприклади нижче в цьому випадку.

Складні програми та застарілі версії Python (2.6 та нижче): Popen

Якщо вам потрібна глибока сумісність назад, або якщо вам потрібна більш досконала функціональність, ніж check_outputнадається, вам доведеться працювати безпосередньо з Popenоб’єктами, які інкапсулюють API низького рівня для підпроцесів.

PopenКонструктор приймає або одну команду без аргументів, або список , який містить команду в якості першого елемента, за яким слід будь-яку кількість аргументів, кожен з яких в якості окремого елемента в списку. shlex.splitможе допомогти проаналізувати рядки у відповідно відформатованих списках. PopenОб'єкти також приймають безліч різних аргументів для управління IO процесів та конфігурації низького рівня.

Надіслати вхід і захопити вихідний сигнал 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

Note відповідь Аарон Холла , який вказує на те, що на деяких системах, вам може знадобитися набір stdout, stderrі stdinвсе PIPE(або DEVNULL) , щоб отримати , communicateщоб працювати на всіх.

У деяких рідкісних випадках вам може знадобитися складне захоплення виходу в реальному часі. Відповідь Vartec пропонує шлях вперед, але інші способи, ніж communicateсхильні до тупикових ситуацій, якщо їх не використовувати обережно.

Як і у всіх перерахованих вище функціях, коли безпека не викликає занепокоєння, ви можете запускати більш складні команди оболонки, передаючи їх shell=True.

Примітки

1. Запуск команд оболонки: shell=Trueаргумент

Як правило, кожен виклик run, check_outputабо Popenконструктор виконує одну програму . Це означає, що немає фантазійних стилів у стилі баш. Якщо ви хочете запустити складні команди оболонки, ви можете передати shell=True, які підтримують усі три функції.

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

run(cmd, [stdout=etc...], input=other_output)

Або

Popen(cmd, [stdout=etc...]).communicate(other_output)

Спокуса безпосередньо підключити труби сильна; протистояти цьому. В іншому випадку, ви , ймовірно , побачити тупики або повинні зробити Hacky таких речей , як це .

2. Однозначні міркування

check_outputповертає рядок у Python 2, але bytesоб’єкт у Python 3. Варто взяти трохи часу, щоб дізнатися про unicode, якщо ви ще цього не зробили.


5
І з, check_output()і communicate()вам доведеться чекати, поки процес закінчиться, і poll()ви отримаєте вихід у міру його надходження. Дійсно залежить, що вам потрібно.
vartec

2
Не впевнений, чи це стосується лише пізніших версій Python, але змінна outбула <class 'bytes'>для мене типовою. Щоб отримати вихід у вигляді рядка, я повинен був розшифрувати його перед друком так:out.decode("utf-8")
PolyMesh

1
@par Це не працює для вас, коли ви проходите shell=True? Це працює для мене. Вам не потрібно, shlex.splitколи проходите shell=True. shlex.splitпризначений для команд без оболонок. Я думаю, що я вийду це трохи, тому що це замулює води.
відправник

2
Python 3.5+ дозволяє аргумент ключового слова, universal_newlines=Trueякий дозволяє переходити та виводити рядки Unicode в кодування за замовчуванням системи. У 3.7 це було перейменовано на більш розумне text=True.
трійка

2
Для Python 3.6+ ви можете використовувати encodingпараметр, subprocess.runа result.stdout.decode('utf-8')не використовувати subprocess.run(['ls', '-l'], stdout=subprocess.PIPE, encoding='utf-8').
П’єр

191

Це простіше, але працює лише на Unix (включаючи Cygwin) та Python2.7.

import commands
print commands.getstatusoutput('wc -l file')

Він повертає кортеж з (return_value, output).

Для рішення, яке працює і в Python2, і в Python3, використовуйте subprocessзамість цього модуль:

from subprocess import Popen, PIPE
output = Popen(["date"],stdout=PIPE)
response = output.communicate()
print response

31
Зараз застарілий, але дуже корисний для старих версій python без subprocess.check_output
static_rtti

22
Зауважте, що це специфічно для Unix. Наприклад, це не вдасться в Windows.
Zitrax

4
+1 Я повинен працювати над старовинною версією python 2.4, і це було ДУЖЕ корисно
javadba

1
Що таке чувак PIPE, покажіть повний код: subprocess.PIPE
Kyle Bridenstine

@KyleBridenstine ви можете редагувати відповіді.
Борис

106

Щось схоже:

def runProcess(exe):    
    p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    while(True):
        # returns None while subprocess is running
        retcode = p.poll() 
        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,

Не забудьте здійснити якусь активну петлю, щоб отримати вихід, щоб уникнути потенційного тупику waitта callфункцій.
Андре Карон

@Silver Light: ваш процес, ймовірно, чекає на введення від користувача. Спробуйте надати PIPEзначення stdinта закрийте цей файл, як тільки Popenповернеться.
Андре Карон

4
-1: це нескінченна петля, якщо retcodeє 0. Чек повинен бути if retcode is not None. Ви не повинні давати порожні рядки (навіть порожній рядок, по крайней мере один символ «\ п»): if line: yield line. Дзвінокp.stdout.close() в кінці.
jfs

2
Я спробував код з ls -l / dirname, і він переривається після перерахування двох файлів, в той час як у каталозі є набагато більше файлів
Vasilis

3
@fuenfundachtzig: .readlines()не повернеться до тих пір, поки не буде прочитаний весь висновок, і тому він перерветься на великий вихід, який не вміщується в пам'яті. Також щоб уникнути пропущених завантажених даних після завершення підпроцесу, має бути аналогif retcode is not None: yield from p.stdout.readlines(); break
jfs

67

Відповідь Vartec не читає всіх рядків, тому я зробив версію, яка:

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)

6
ви можете використовувати return iter(p.stdout.readline, b'')замість циклу while
jfs

2
Це досить круте використання iter, не знав цього! Я оновив код.
Макс Екман

Я впевнений, що stdout зберігає весь вихід, це об'єкт потоку з буфером. Я використовую дуже схожу техніку для виснаження всіх решти результатів після завершення роботи Popen, а в моєму випадку, використовуючи опитування () та лінійку читання під час виконання, щоб також захопити вихід в реальному часі.
Макс Екман

Я видалив свій оманливий коментар. Я можу підтвердити, p.stdout.readline()може повернути не порожній раніше буферний вихід, навіть якщо дочірній процес вже завершився ( p.poll()ні None).
jfs

Цей код не працює. Дивіться тут stackoverflow.com/questions/24340877/…
thang

61

Це складне, але дуже просте рішення, яке працює в багатьох ситуаціях:

import os
os.system('sample_cmd > tmp')
print open('tmp', 'r').read()

Тимчасовий файл (тут є tmp) створюється з виведенням команди, і ви можете прочитати з нього потрібний результат.

Додаткова примітка з коментарів: Ви можете видалити файл tmp у разі разової роботи. Якщо вам потрібно зробити це кілька разів, видаляти tmp не потрібно.

os.remove('tmp')

5
Гакі, але дуже простий + працює де завгодно .. можна поєднувати його з mktempтим, щоб він працював у потокових ситуаціях, я думаю
Пракаш Раджагаопал

2
Можливо, найшвидший метод, але краще додати, os.remove('tmp')щоб зробити його "безфайловим".
XuMuK

@XuMuK Ви маєте рацію у випадку одноразової роботи. Якщо це повторювана робота, можливо, видалення не потрібно
Мехді Саман Буй

1
погано для одночасності, погано для рецензуючих функцій, погано для того, щоб не виходити з системи, як це було до запуску (без очищення)
2mia

1
@ 2mia Очевидно, що це просто з причини! Якщо ви хочете використовувати файл як вид спільної пам'яті для одночасного читання та запису, це не гарний вибір. Але, для с.т. як, наприклад, вихід команди (наприклад, ls або find або ...), це може бути хорошим і швидким вибором. До речі, якщо вам потрібно швидко вирішити просту проблему, це найкраще, на мою думку. Якщо вам потрібен конвеєр, підпроцес працює для вас більш ефективно.
Мехді Саман Буй

44

У мене була така ж проблема, але я зрозумів дуже простий спосіб зробити це:

import subprocess
output = subprocess.getoutput("ls -l")
print(output)

Сподіваюся, це допоможе

Примітка. Це рішення є специфічним для Python3, оскільки subprocess.getoutput()не працює в Python2


Як це вирішує проблему ОП? Будь ласка, докладно.
RamenChef

4
Він повертає результат команди як рядок, такий же простий
azhar22k

1
Звичайно, print - це твердження на Python 2. Ви повинні мати можливість зрозуміти, що це відповідь Python 3.

2
@Dev друк (и) дійсні python 2. subprocess.getoutput - ні.
user48956

2
У більшості випадків використання люди, що, ймовірно, захочуть: легко запам'ятовується, не потрібно розшифровувати результати тощо. Дякую.
bwv549

18

Ви можете використовувати наступні команди для запуску будь-якої команди оболонки. Я використовував їх на ubuntu.

import os
os.popen('your command here').read()

Примітка: Це застаріло, оскільки python 2.6. Тепер ви повинні використовувати subprocess.Popen. Нижче наведено приклад

import subprocess

p = subprocess.Popen("Your command", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")

2
Застаріло з версії 2.6 - docs.python.org/2/library/os.html#os.popen
Filippo Vitale

1
@FilippoVitale Спасибі Я не знав, що це застаріло.
Мухаммед Хассан

1
Відповідно до raspberrypi.stackexchange.com/questions/71547/… os.popen() застаріло в Python 2.6, але в Python 3.x не застаріло, оскільки в 3.x реалізовано за допомогою subprocess.Popen().
JL

12

Ваш Пробіг, травня, я намагався @ snderle повернутись на рішення 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's.

Щоб зупинити спливаючі вікна консолі (для 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')

1
Цікаво - це повинна бути річ Windows. Я додам примітку, що вказує на це, якщо люди отримують подібні помилки.
senderle

використовувати DEVNULLзамість того, subprocess.PIPEякщо ви не пишете / не читаєте з труби, інакше ви можете повісити дочірній процес.
jfs

10

Я мав дещо інший аромат тієї ж проблеми з такими вимогами:

  1. Знімайте та повертайте повідомлення STDOUT у міру їх накопичення в буфері STDOUT (тобто в режимі реального часу).
    • @vartec вирішив це Pythonically за допомогою використання генераторів і
      ключового слова "вихід" вище
  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)

1
Ви не проти пояснити, як додавання режиму сну (.1) не витрачає циклів процесора?
Моатаз Ельмасрі

2
Якби ми продовжували дзвінки p.poll()без сну між дзвінками, ми витрачали б цикли процесора, викликаючи цю функцію мільйони разів. Натомість ми "заглушуємо" свою петлю, повідомляючи ОС, що нам не потрібно турбуватися протягом наступної 1/10 секунди, щоб вона могла виконувати інші завдання. (Можливо, що p.poll () теж спить, що робить нашу заяву про сон зайвою).
The Aelfinn

5

Розбиття початкової команди для 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...'

Без shlex.split()коду виглядало б так

res = check_output([
    'git', 
    'log', 
    '-n', 
    '5', 
    '--since', 
    '5 years ago', 
    '--until', 
    '2 year ago'
])
print(res)
>>> b'commit 7696ab087a163e084d6870bb4e5e4d4198bdc61a\nAuthor: Artur Barseghyan...'

1
shlex.split()це зручність, особливо якщо ви не знаєте, як саме працює цитування в оболонці; але перевести цей рядок в список вручну ['git', 'log', '-n', '5', '--since', '5 years ago', '--until', '2 year ago']зовсім не складно, якщо ви розумієте, що цитувати.
трійка

4

Якщо вам потрібно запустити команду shell на декількох файлах, це зробило для мене трюк.

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

Правка: Щойно побачив рішення Макса Перссона з пропозицією Дж. Ф. Себастьяна. Пішли вперед і включили це.


Popenприймає або рядок, але тоді вам потрібно shell=True, або список аргументів, і в цьому випадку вам слід передати ['nm', filename]замість рядка. Останнє є кращим, оскільки оболонка додає складності, не надаючи тут ніякої цінності. Передавання рядка, shell=Trueмабуть, працює в Windows, але це може змінитися в будь-якій наступній версії Python.
трійка

2

За словами @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


Ви винаходите аргументи ключових слів check=True, universal_newlines=True. Іншими словами, subprocess.run()вже робить усе, що робить ваш код.
трійка

1

Якщо ви використовуєте subprocessмодуль python, ви можете окремо обробляти STDOUT, STDERR та код повернення команди. Ви можете побачити приклад повної реалізації команди виклику команд. Звичайно, ви можете продовжити це, try..exceptякщо хочете.

Наведена нижче функція повертає код STDOUT, STDERR та Return, щоб ви могли обробляти їх в іншому сценарії.

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

Ще одна погана реалізація subprocess.run(). Не винаходити колесо.
трійка

0

наприклад, виконати ('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://stackoverflow.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 ""

0

Вихід можна перенаправити на текстовий файл, а потім прочитати його назад.

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

Звичайно, це може, але чому б ти цього хотів; і чому б ти використовував оболонку, а не проходив stdout=temp_file?
трійка

Насправді, в цілому ви маєте рацію, але на моєму прикладі, ecls.exeздається, розгортається інший інструмент командного рядка, тому простий спосіб іноді не працював.
MR

0

просто написав невеликий скрипт 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)"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.