[PYTHON] Behandeln Sie externe Befehle wie Funktionen mit sh

shIch habe eine Bibliothek ausprobiert, die durch Importieren des externen Befehls verwendet werden kann, als wäre es eine Funktion.

>>> from sh import echo
>>> echo('hello', 'world')
hello world

Installation

pipKann mit installiert werden.

$ pip install sh

Wie benutzt man

Um es zu verwenden, importieren Sie einfach den Befehl, den Sie verwenden möchten, aus dem `` `sh``` Modul und führen Sie ihn aus.

>>> from sh import date
>>> date()
Sonntag, 1. Februar 2015, 22:50:13 Uhr JST

Sie können auch schreiben:

>>> import sh
>>> sh.date()
Sonntag, 1. Februar 2015, 22:50:13 Uhr JST

Streit

Befehlsargumente können als Funktionsargumente übergeben werden.

>>> from sh import echo
>>> echo('hello', 'world')
hello world

Möglichkeit

Optionen können als Schlüsselwortargumente übergeben werden.

>>> from sh import curl
>>> curl('http://google.com/', o='out.html', silent=True, L=True)

Optionen können sowohl als Funktionsargumente als auch als Argumente übergeben werden. Dies sollte für Befehle verwendet werden, bei denen die Option vor dem Argument stehen muss.

>>> curl('-o', 'out.html', '--silent', '-L', 'http://google.com/')

Standardeingabe

Wenn Sie im Schlüsselwortargument `` _in``` eine Zeichenfolge angeben, können Sie diese als Standardeingabe an den Befehl übergeben.

>>> from sh import cat
>>> cat(_in='hello')
hello

_inEs ist auch möglich, iterable for anzugeben.

>>> cat(_in=['hello\n', 'world\n'])
hello
world

Sie können auch ein Dateiobjekt übergeben.

>>> cat(_in=open('test.txt'))
hoge
fuga
piyo

umleiten

Durch Angabe des Dateinamens in den Schlüsselwortargumenten _out``` und _err``` können Standardausgabe und Standardfehler in die Datei umgeleitet werden.

>>> from sh import echo, cat
>>> echo('hello', 'world', _out='hello.txt')

>>> cat('hello.txt')
hello world

_out 、_errEs ist auch möglich, eine Rückruffunktion an zu übergeben.

>>> echo('hello', 'world', _out=lambda s: sys.stdout.write(s.upper()))
HELLO WORLD

Ausgabe-Iterator

Wenn Sie das Schlüsselwortargument `` `_iterangeben, können Sie einen Iterator erhalten, der das Ergebnis zeilenweise zurückgibt.tail -fBei einem Befehl, der unbegrenzt ausgegeben wird, wird der Prozess nicht beendet._iter```Sie müssen die Ausgabe vom Iterator mit abrufen.

>>> from sh import seq
>>> seq(1, 3)
1
2
3

>>> for n in seq(1, 3, _iter=True):
...     print n.strip()
... 
1
2
3

Rohr

Durch Verschachtelungsfunktionen kann die Ausgabe einer Funktion an die Eingabe einer anderen Funktion weitergeleitet werden.

>>> from sh import echo, wc
>>> wc(echo('hello'), c=True)
       6

Wenn Sie es zu stark verschachteln, wird es schwer zu verstehen sein, so dass das von [toolz](https://github.com/pytoolz/toolz) in [Vorheriger Artikel](http://qiita.com/atsaki/items/e520cb6b3f3ae1541cfa) eingeführt wurde. Es scheint gut zu sein, es in Kombination mit der Funktion `` pipe```, `` thread_first``` usw. zu verwenden.

>>> pipe('hello', echo, lambda x: wc(x, c=True))
       6

>>> thread_first('hello', echo, (wc, '-c'))
       6

shStandardmäßig übergibt die Pipe das Ergebnis an den nächsten Befehl, nachdem der vorherige Befehl beendet wurde. tail -fWenn Sie einen Befehl ausführen, der nicht wie endet, wird er nicht zurückgegeben, also ein Schlüsselwortargument_pipeIch muss Ihnen sagen, was in der Pipeline vor sich geht.

>>> from sh import yes, tr
>>> it = tr(yes(), 'y','Y', _iter=True) #NG, weil der Befehl yes nicht endet
>>> it = tr(yes(_piped=True), 'y','Y', _iter=True) #Das ist in Ordnung
>>> it.next()
u'Y\n'

Glob

Wenn Sie ein Sternchen als Funktionsargument übergeben, wird es nicht erweitert.

>>> from sh import ls
>>> ls('./*') #Weil es nicht bereitgestellt wird./*Versuche zu finden sind normalerweise erfolglos.

Verwenden Sie `sh.glob``` zum Extrahieren. ** Verwenden Sie nicht die Standardbibliothek `glob.glob```. ** ** **

>>> from sh import ls, glob
>>> ls(glob('./*')) # sh.Mit glob erweitern

Hintergrundausführung

Standardmäßig wartet die Funktion `sh``` darauf, dass der Prozess beendet wird. Wenn Sie es im Hintergrund ausführen möchten, fügen Sie der Option _bg = True``` hinzu. Sie können warten, bis der im Hintergrund ausgeführte Prozess mit der Methode `` wait``` endet.

>>> from sh import sleep
>>> sleep(10)              #10 Sekunden lang blockieren
>>> p = sleep(10, _bg=True) #Werde bald zurück sein
>>> p.wait()               #Warten Sie, bis der Vorgang beendet ist

Code und Fehlerbehandlung beenden

Der Endcode des Befehls kann mit `` `exit_code``` erhalten werden. Wenn es normal endet, wird es normalerweise 0.

>>> from sh import ls
>>> output = ls('/tmp')
>>> output.exit_code
0

Eine Ausnahme wird ausgelöst, wenn der Befehl abnormal beendet wird. Ein bestimmter Endcode kann mit `ErrorReturnCode_ <Endcode>` erfasst werden. `` `ErrorReturnCode``` erfasst alle Endcodes.

>>> from sh import ls, ErrorReturnCode_1
>>> try:
...     output = ls('/hogehoge')
... except ErrorReturnCode_1:
...     print "return code is 1"
... 
return code is 1

>>> try:
...     output = ls('/hogehoge')
... except ErrorReturnCode as e:
...     print 'cmd:', e.full_cmd
...     print 'returncode:', e.exit_code
...     print 'stdout:', e.stdout
...     print 'stderr:', e.stderr
... 
cmd: /bin/ls /hogehoge
returncode: 1
stdout: 
stderr: ls: /hogehoge: No such file or directory

Geben Sie für Befehle, die einen Endcode ungleich Null zurückgeben, auch wenn der Befehl erfolgreich ist, eine Liste von Endcodes an, wenn der Befehl im Schlüsselwortargument `` `_ok_code``` erfolgreich ist.

Signal

Sie können den Prozess mit den folgenden drei Methoden signalisieren:

Wenn der Prozess mit einem Signal endet, tritt `SignalException_ <Signalnummer>` auf, wenn `wait``` ausgeführt wird. Außerdem ist `exit_code``` die negative Signalnummer.

>>> from sh import sleep
>>> p = sleep(10, _bg=True)
>>> p.kill()
>>> try:
...     p.wait()
... except ErrorReturnCode as e:
...     print 'cmd:', e.full_cmd
...     print 'returncode:', e.exit_code
...     print 'stdout:', e.stdout
...     print 'stderr:', e.stderr
... 
cmd: /bin/sleep 10
returncode: -9
stdout: 
stderr:

Wie es funktioniert

Da die externen Befehle, die verwendet werden können, je nach Umgebung unterschiedlich sind, ist ersichtlich, dass `` `sh``` das dem externen Befehl entsprechende Objekt dynamisch erstellt.

Der Mechanismus zum Importieren beliebiger Befehle ist im folgenden Code grob implementiert. Der Punkt ist, `sys.modules [__ name __]` durch eine Klasse zu ersetzen, die `` ModuleType``` beim Importieren von Modulen erbt.

mysh.py


import sys
import subprocess
from types import ModuleType

class MySh(ModuleType):
    def __init__(self, self_module):
        self.__name__ = self_module.__name__
                                       
    def __getattr__(self, name):
        def command(*args):
            return subprocess.check_output([name] + list(args))
        return command

mysh = sys.modules[__name__]
sys.modules[__name__] = MySh(mysh)

Sie können dieses Modul verwenden, um `` `echo``` wie folgt zu importieren und auszuführen:

>>> from mysh import echo
>>> echo('hello', 'world')
'hello world\n'

Referenzmaterial

Recommended Posts

Behandeln Sie externe Befehle wie Funktionen mit sh
Skripterstellung mit externen Fertigern