Uruchamianie polecenia powłoki i przechwytywanie wyjścia

Chcę napisać funkcję, która wykona polecenie powłoki i zwróci jej wyjście jako łańcuch , bez względu na to, czy jest to Komunikat o błędzie czy sukcesie. Chcę tylko uzyskać taki sam wynik, jaki uzyskałbym za pomocą wiersza poleceń.

Jaki byłby przykład kodu, który zrobiłby coś takiego?

Na przykład:

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'
Author: martineau, 2011-01-21

18 answers

We wszystkich oficjalnie utrzymywanych wersjach Pythona, najprostszym podejściem jest użycie subprocess.check_output funkcja:

>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

check_output uruchamia pojedynczy program, który pobiera tylko argumenty jako dane wejściowe.1 zwraca wynik dokładnie tak, jak Wydrukowano do stdout. Jeśli chcesz zapisać dane wejściowe do stdin, przejdź do sekcji run lub Popen. Jeśli chcesz wykonać złożone polecenia powłoki, zobacz notatkę shell=True na końcu tej odpowiedzi.

Funkcja check_output działa we wszystkich oficjalnie utrzymywane wersje Pythona. Jednak w przypadku nowszych wersji dostępne jest bardziej elastyczne podejście.

[91]}współczesne wersje Pythona (3.5 lub nowsze): run

Jeśli używasz Pythona 3.5+ I nie potrzebujesz kompatybilności wstecznej, nowa funkcja run jest zalecana przez oficjalną dokumentację dla większości zadań. Zapewnia bardzo ogólne, wysokiego poziomu API dla modułu subprocess. Aby przechwycić wyjście programu, przekaż subprocess.PIPE Flaga do argumentu słowa kluczowego stdout. Następnie uzyskaj dostęp do atrybutu stdout zwracanego CompletedProcess obiekt:

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

Wartość zwracana jest obiektem bytes, więc jeśli chcesz mieć odpowiedni ciąg znaków, musisz go decode. Przy założeniu, że wywołany proces zwróci kodowany w UTF-8 ciąg znaków:

>>> result.stdout.decode('utf-8')
'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'
To wszystko może być skompresowane do jednej liniowej w razie potrzeby:
>>> 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'

Jeśli chcesz przekazać dane wejściowe do stdin procesu, możesz przekazać obiekt bytes do słowa kluczowego input argument:

>>> cmd = ['awk', 'length($0) > 5']
>>> ip = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=ip)
>>> result.stdout.decode('utf-8')
'foofoo\n'

Możesz przechwytywać błędy, przekazując stderr=subprocess.PIPE (przechwytywanie do result.stderr) lub stderr=subprocess.STDOUT (przechwytywanie do result.stdout wraz ze zwykłym wyjściem). Jeśli chcesz run wyrzucić wyjątek, gdy proces zwróci niezerowy kod zakończenia, możesz przekazać check=True. (Lub możesz sprawdzić returncode atrybut result powyżej.) Gdy bezpieczeństwo nie jest problemem, można również uruchomić bardziej złożone polecenia powłoki, przekazując shell=True, jak opisano na końcu tej odpowiedzi.

Późniejsze wersje Pythona usprawniają wyżej. W Pythonie 3.7+ powyższa jednowierszowa może być zapisana w następujący sposób:

>>> subprocess.run(['ls', '-l'], capture_output=True, text=True).stdout
'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

Użycie run w ten sposób dodaje tylko trochę złożoności, w porównaniu do starego sposobu robienia rzeczy. Ale teraz możesz zrobić prawie wszystko, co musisz zrobić za pomocą samej funkcji run.

Starsze wersje Pythona (3-3.4): więcej o check_output

Jeśli używasz starszej wersji Pythona lub potrzebujesz skromnej kompatybilności wstecznej, możesz użyć funkcji check_output, Jak krótko opisano powyżej. Informatyka jest dostępny od wersji Python 2.7.

subprocess.check_output(*popenargs, **kwargs)  

Pobiera te same argumenty co Popen (patrz niżej) i zwraca łańcuch zawierający wyjście programu. Początek tej odpowiedzi zawiera bardziej szczegółowy przykład użycia. W Pythonie 3.5+, check_output jest równoznaczne z wykonaniem run z check=True i stdout=PIPE i zwróceniem tylko atrybutu stdout.

Możesz przekazać stderr=subprocess.STDOUT, aby upewnić się, że komunikaty o błędach są zawarte w zwracanym wyjściu. Gdy bezpieczeństwo nie jest problemem, można również Uruchom bardziej złożone polecenia powłoki, przekazując shell=True, jak opisano na końcu tej odpowiedzi.

Jeśli chcesz przesyłać dane z stderr lub przekazać dane wejściowe procesowi, check_output nie będzie gotowe do zadania. Zobacz przykłady Popen poniżej w tym przypadku.

[91]}złożone aplikacje i starsze wersje Pythona (2.6 i poniżej): Popen

Jeśli potrzebujesz głębokiej kompatybilności wstecznej lub jeśli potrzebujesz bardziej wyrafinowanej funkcjonalności niż check_output lub run, będziesz musiał pracować bezpośrednio z Popen obiekty, które zawierają niskopoziomowe API dla podprocesów.

Konstruktor Popen akceptuje albo pojedyncze polecenie bez argumentów, albo listę zawierającą polecenie jako pierwszą pozycję, po której następuje dowolna liczba argumentów, każdy jako oddzielny element listy. shlex.split może pomóc w parsowaniu łańcuchów do odpowiednio sformatowanych list. Popen obiekty akceptują również host różnych argumentów do zarządzania procesami i niskopoziomowymi konfiguracja.

Aby wysyłać dane wejściowe i przechwytywać dane wyjściowe, communicate jest prawie zawsze preferowaną metodą. Jak w:

output = subprocess.Popen(["mycmd", "myarg"], 
                          stdout=subprocess.PIPE).communicate()[0]

Lub

>>> import subprocess
>>> p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE, 
...                                    stderr=subprocess.PIPE)
>>> out, err = p.communicate()
>>> print out
.
..
foo

Jeśli ustawisz stdin=PIPE, communicate pozwala również na przekazywanie danych do procesu poprzez 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

Uwaga odpowiedź Aarona Halla , która wskazuje, że w niektórych systemach może być konieczne ustawienie stdout, stderr, i stdin wszystkie do PIPE (lub DEVNULL), aby communicate w ogóle zadziałały.

W niektórych rzadkich przypadkach, może być konieczne złożone, w czasie rzeczywistym przechwytywanie danych wyjściowych. odpowiedź Vartec sugeruje drogę naprzód, ale metody inne niż communicate są podatne na blokady, jeśli nie są używane ostrożnie.

Podobnie jak w przypadku wszystkich powyższych funkcji, gdy bezpieczeństwo nie jest problemem, można uruchomić bardziej złożone polecenia powłoki przekazując shell=True.

Uwagi

1. Uruchamianie poleceń powłoki: argument shell=True

Normalnie każde wywołanie do run, check_output, lub konstruktor Popen wykonuje pojedynczy program . Że czyli żadnych fajek w stylu bash. Jeśli chcesz uruchomić złożone polecenia powłoki, możesz przekazać shell=True, które obsługują wszystkie trzy funkcje. Na przykład:

>>> subprocess.check_output('cat books/* | wc', shell=True, text=True)
' 1299377 17005208 101299376\n'
Jednak robienie tego rodzi obawy o bezpieczeństwo. Jeśli robisz coś więcej niż lekkie Skrypty, możesz lepiej wywołać każdy proces osobno i przekazać dane wyjściowe z każdego jako wejście do następnego, za pomocą
run(cmd, [stdout=etc...], input=other_output)

Lub

Popen(cmd, [stdout=etc...]).communicate(other_output)
[81]}pokusa bezpośredniego łączenia rur jest silna; oprzyj się jej. W przeciwnym razie prawdopodobnie zobaczysz impasy lub będziesz musiał robić trudne rzeczy, takie jak to .
 1310
Author: senderle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-03 15:03:11

Jest to o wiele łatwiejsze, ale działa tylko na Uniksie (w tym Cygwin) i Python2.7.

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

Zwraca krotkę z (return_value, output).

Dla rozwiązania, które działa zarówno w Python2 jak i Python3, użyj zamiast tego modułu subprocess:

from subprocess import Popen, PIPE
output = Popen(["date"],stdout=PIPE)
response = output.communicate()
print response
 197
Author: byte_array,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-12 16:36:40

Coś w tym stylu:

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

Zauważ, że Przekierowuję stderr na stdout, może to nie jest dokładnie to, czego chcesz, ale chcę również komunikaty o błędach.

Ta funkcja generuje linię po linii, gdy przychodzą (normalnie musiałbyś poczekać na zakończenie podprocesu, aby uzyskać wyjście jako całość).

W Twoim przypadku użycie byłoby:

for line in runProcess('mysqladmin create test -uroot -pmysqladmin12'.split()):
    print line,
 112
Author: vartec,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-12-28 10:30:33

Odpowiedź Varteca nie odczytuje wszystkich linijek, więc zrobiłem wersję, która zrobiła:

def run_command(command):
    p = subprocess.Popen(command,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)
    return iter(p.stdout.readline, b'')

Użycie jest takie samo jak zaakceptowana odpowiedź:

command = 'mysqladmin create test -uroot -pmysqladmin12'.split()
for line in run_command(command):
    print(line)
 72
Author: Max Ekman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:24

To jest trudne ale super proste rozwiązanie, które sprawdza się w wielu sytuacjach:

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

Plik tymczasowy (tutaj jest tmp) jest tworzony z wyjściem polecenia i można z niego odczytać żądane wyjście.

Extra notka z komentarzy: Plik tmp można usunąć w przypadku zadania jednorazowego. Jeśli musisz to zrobić kilka razy, nie ma potrzeby usuwania tmp.

os.remove('tmp')
 65
Author: Mehdi Saman Booy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-27 07:19:52

Miałem ten sam problem, ale wymyśliłem bardzo prosty sposób na zrobienie tego:

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

Hope it helps out

Uwaga: To rozwiązanie jest specyficzne dla Python3, ponieważ subprocess.getoutput() nie działa w Python2

 65
Author: azhar22k,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-12 14:42:12

Możesz użyć następujących poleceń do uruchomienia dowolnego polecenia powłoki. Używałem ich na ubuntu.

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

Uwaga: jest to przestarzałe od wersji Pythona 2.6. Teraz musisz użyć subprocess.Popen. Poniżej znajduje się przykład

import subprocess

p = subprocess.Popen("Your command", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")
 21
Author: Muhammad Hassan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-18 05:41:10

Twój przebieg może się różnić, próbowałem spin @ senderle na rozwiązaniu Vartec w Windows na Pythonie 2.6.5, ale dostawałem błędy, i żadne inne rozwiązania nie działały. Mój błąd to: WindowsError: [Error 6] The handle is invalid.

Odkryłem, że musiałem przypisać PIPE do każdego uchwytu, aby zwrócił oczekiwane wyjście - poniższe zadziałało dla mnie.

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

I wywołanie w ten sposób, ([0] otrzymuje pierwszy element krotki, stdout):

run_command('tracert 11.1.0.1')[0]

Po dowiedzeniu się więcej, uważam, że potrzebuję tych argumentów, ponieważ Pracuję nad niestandardowym systemem, który używa różnych uchwytów, więc musiałem bezpośrednio kontrolować wszystkie choroby weneryczne.]}

Aby zatrzymać wyskakujące okienka konsoli (w systemie Windows), wykonaj następujące czynności:

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')
 12
Author: Aaron Hall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-07 15:21:14

Miałem nieco inny smak tego samego problemu z następującymi wymaganiami:

  1. przechwytywanie i zwracanie wiadomości STDOUT, gdy gromadzą się one w buforze STDOUT (np. w czasie rzeczywistym).
    • @vartec rozwiązał ten problem używając generatorów i "wydajności"
      słowo kluczowe powyżej
  2. wypisuje wszystkie linie Wyjścia ( nawet jeśli proces zakończy działanie przed buforem wyjścia może być w pełni odczytany )
  3. Nie marnuj cykli procesora badanie procesu przy wysokiej częstotliwości
  4. Sprawdź kod powrotu podprocesu
  5. Print STDERR (oddzielony od STDOUT) jeśli otrzymamy niezerowy kod zwracający błąd.

Połączyłem i poprawiłem poprzednie odpowiedzi, aby uzyskać następujące odpowiedzi:

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

Ten kod będzie wykonywany tak samo jak poprzednie odpowiedzi:

for line in run_command(cmd):
    print(line)
 11
Author: The Aelfinn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-18 03:31:23

Rozdzielenie komendy początkowej dla subprocess może być trudne i uciążliwe.

Użyj shlex.split(), aby pomóc sobie.

Przykładowe polecenie

git log -n 5 --since "5 years ago" --until "2 year ago"

Kod

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...'

BEZ shlex.split() kod wyglądałby następująco

res = check_output([
    'git', 
    'log', 
    '-n', 
    '5', 
    '--since', 
    '5 years ago', 
    '--until', 
    '2 year ago'
])
print(res)
>>> b'commit 7696ab087a163e084d6870bb4e5e4d4198bdc61a\nAuthor: Artur Barseghyan...'
 5
Author: Artur Barseghyan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-18 20:05:19

Jeśli musisz uruchomić polecenie powłoki na wielu plikach, To mi się udało.

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

Edit: właśnie zobaczyłem rozwiązanie Maxa Perssona z sugestią J. F. Sebastiana. / Align = "left" /

 4
Author: Ethan Strider,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-01 15:54:55

Według @senderle, jeśli używasz python3. 6 Jak ja:

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

Będzie działać dokładnie tak, jak uruchomisz polecenie w bash

 3
Author: Neo li,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-20 06:47:44

Tutaj rozwiązanie, działające, jeśli chcesz wydrukować wyjście, gdy proces jest uruchomiony lub nie.


Dodałem również bieżący katalog roboczy, przydał mi się nie raz.


Mam nadzieję, że rozwiązanie komuś pomoże:).

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
 2
Author: Joy Jedidja Ndjama,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-29 23:32:10

Jeśli używasz modułu Pythona subprocess, możesz obsługiwać STDOUT, STDERR i Kod polecenia osobno. Możesz zobaczyć przykład pełnej implementacji wywołującego polecenia. Oczywiście możesz go rozszerzyć za pomocą try..except, jeśli chcesz.

Poniższa funkcja zwraca kod STDOUT, STDERR I Return, abyś mógł obsłużyć je w innym skrypcie.

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
 1
Author: milanbalazs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-20 11:24:47

Eg, execute ('ls-ahl') zróżnicowane trzy / cztery możliwe zwroty i platformy OS:

  1. brak wyjścia, ale Uruchom pomyślnie
  2. wyjście pustej linii, Uruchom pomyślnie
  3. run failed
  4. wypuść coś, Uruchom pomyślnie

Funkcja poniżej

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
Author: Jerry T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-02 21:55:38

Wyjście może zostać przekierowane do pliku tekstowego, a następnie odczytane z powrotem.

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))
 0
Author: Masoud Rahimi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-22 15:06:06

Właśnie napisałem mały skrypt bash, aby to zrobić za pomocą 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)"
 0
Author: harish2704,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-13 13:06:25

Chciałbym zaproponować simppl jako opcję do rozważenia. Jest to moduł, który jest dostępny przez pypi: pip install simppl i został uruchomiony na python3.

simppl pozwala użytkownikowi uruchamiać polecenia powłoki i odczytywać dane wyjściowe z ekranu.

Twórcy sugerują trzy rodzaje przypadków użycia:

  1. najprostsze użycie będzie wyglądało tak:
    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. aby uruchomić wiele poleceń jednocześnie użycie:
    commands = ['<YOUR_FIRST_OS_COMMAND>', '<YOUR_SECOND_OS_COMMAND>']
    max_number_of_processes = 4
    sp.run_parallel(commands, max_number_of_processes) ```

  1. wreszcie, jeśli twój projekt używa modułu cli, możesz uruchomić bezpośrednio inny command_line_tool jako część potoku. Inne narzędzie będzie być uruchamiany z tego samego procesu, ale będzie on wyświetlany z dzienników jako kolejne polecenie w rurociągu. Umożliwia to płynniejsze debugowanie i refaktoryzacja narzędzi wywołanie innych narzędzi.
    from example_module import example_tool
    sp.print_and_run_clt(example_tool.run, ['first_number', 'second_nmber'], 
                                 {'-key1': 'val1', '-key2': 'val2'},
                                 {'--flag'}) ```

Zauważ, że drukowanie na STDOUT/STDERR odbywa się za pomocą modułu logging Pythona.


Oto Pełny kod pokazujący jak działa 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')
 0
Author: 0x90,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-19 09:59:46