Python

Python je multiplatformní jazyk oblíbený pro svou jednoduchost a stručnost. Jeho hlavní předností je srozumitelná a čistá syntaxe. Díky své jednoduchosti bývá označován jako jeden z nejvhodnějších programovacích jazyků pro začátečníky.

Hlavní funkcí, kterou bychom měli pro spouštění sheelových příkazů používat v Pythonu subprocess.run(). Ale než se k ní dostaneme, je vhodné začít funkcí subprocess.Popen, u které narozdíl od prvního příkazu můžeme používat shellovou pipe.

Jde si všimnout, že v příkazu subprosses se používá stdout a stderr s PIPE. Pipe pak jde číst příkazem .communicate().

import subprocess
process = subprocess.Popen(['echo', 'More output'],
                     stdout=subprocess.PIPE, 
                     stderr=subprocess.PIPE)
stdout, stderr = process.communicate()
print(stdout, stderr)

Výstupem bude:

(b'More output\n', b'')

Stdout jde použít i bez pipe například pro ukládání do souboru:

with open('test.txt', 'w') as f:
    process = subprocess.Popen(['ls', '-l'], stdout=f)

Co nejspíš čtenář zaznamenal je to, že výstup příkazů z output je typu bytes. To lze řešit například překodováním do utf-8 pomocí stdout.decode('utf-8') nebo přidáním universal_newlines=True, když voláme subprocess.Popen.

Pokud máme program, kde periodicky obnovujeme status v běhu programu, můžeme to řešit while cyklem a pomocí funkce .poll(), která kontroluje návratový status příkazu.

process = subprocess.Popen(['ping', '-c 4', 'python.org'], 
                           stdout=subprocess.PIPE,
                           universal_newlines=True)

while True:
    output = process.stdout.readline()
    print(output.strip())
    # Do something else
    return_code = process.poll()
    if return_code is not None:
        print('RETURN CODE', return_code)
        # Process has finished, read rest of the output 
        for output in process.stdout.readlines():
            print(output.strip())
        break

V případě, že proces vrací None, pokračuje se v běhu. O přečtení jednoho řádku se stará process.stdout.readline(), o přečtění všech řádků po dokončení procesu process.stdout.readlines():

PING python.org (45.55.99.72) 56(84) bytes of data.
64 bytes from 45.55.99.72 (45.55.99.72): icmp_seq=1 ttl=51 time=117 ms
64 bytes from 45.55.99.72 (45.55.99.72): icmp_seq=2 ttl=51 time=118 ms
64 bytes from 45.55.99.72 (45.55.99.72): icmp_seq=3 ttl=51 time=117 ms
64 bytes from 45.55.99.72 (45.55.99.72): icmp_seq=4 ttl=51 time=118 ms

--- python.org ping statistics ---
RETURN CODE 0
4 packets transmitted, 4 received, 0% packet loss, time 3001ms
rtt min/avg/max/mdev = 117.215/117.874/118.358/0.461 ms

Subprocess.run() je doporučovaný způsob jak spouštět jeden příkaz, u kterého stačí prosté vyčkávání na jeho dokončení:

process = subprocess.run(['echo', 'Even more output'], 
                         stdout=subprocess.PIPE, 
                         universal_newlines=True)
print(process)

Output je tento:

CompletedProcess(args=['echo', 'Even more output'], returncode=0, stdout='Even more output\n')

Někdy chceme s programem komunikovat a interaktivně zadávat něco na vstup. Příklad ukazuje, že i toto lze velice jednoduše řešit.

import subprocess

ssh = subprocess.Popen(["ssh", "-i .ssh/id_rsa", "user@host"],
                        stdin =subprocess.PIPE,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE,
                        universal_newlines=True,
                        bufsize=0)

# Send ssh commands to stdin
ssh.stdin.write("uname -a\n")
ssh.stdin.write("uptime\n")
ssh.stdin.close()

# Fetch output
for line in ssh.stdout:
    print(line.strip())