[PYTHON] Traitez les commandes externes comme des fonctions avec sh

shJ'ai essayé une bibliothèque qui peut être utilisée en important la commande externe comme s'il s'agissait d'une fonction.

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

Installation

pipPeut être installé en utilisant.

$ pip install sh

Comment utiliser

Pour l'utiliser, importez simplement la commande que vous souhaitez utiliser depuis le module `` sh '' et exécutez-la.

>>> from sh import date
>>> date()
Dimanche 1 février 2015 22:50:13 JST

Vous pouvez également écrire:

>>> import sh
>>> sh.date()
Dimanche 1 février 2015 22:50:13 JST

argument

Les arguments de commande peuvent être passés en tant qu'arguments de fonction.

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

option

Les options peuvent être passées en tant qu'arguments de mot-clé.

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

Les options peuvent être passées comme arguments de fonction ainsi que comme arguments. Cela devrait être utilisé pour les commandes où l'option doit précéder l'argument.

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

Entrée standard

Si vous spécifiez une chaîne de caractères dans l'argument de mot-clé _in```, vous pouvez la transmettre comme entrée standard à la commande.

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

_inIl est également possible de spécifier itérable pour.

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

Vous pouvez également transmettre un objet fichier.

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

réorienter

En spécifiant le nom du fichier dans les arguments de mot-clé _out et `` _err, la sortie standard et l'erreur standard peuvent être redirigées vers le fichier.

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

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

_out 、_errIl est également possible de passer une fonction de rappel à.

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

Itérateur de sortie

Si vous spécifiez l'argument mot-clé `` _iter, vous pouvez obtenir un itérateur qui renvoie le résultat ligne par ligne. tail -fDans le cas d'une commande qui continue à sortir indéfiniment, le processus ne se terminera pas._iter```Vous devez obtenir la sortie de l'itérateur à l'aide de.

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

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

tuyau

En imbriquant des fonctions, la sortie d'une fonction peut être acheminée vers l'entrée d'une autre fonction.

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

Si vous l'emboitez trop, il sera difficile à comprendre, donc le ʻof toolz introduit dans Article précédent Il semble bon de l'utiliser en combinaison avec la fonction pipe```, thread_first```, etc.

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

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

shPar défaut, le tube fonctionne en passant le résultat à la commande suivante une fois la commande précédente terminée. tail -fSi vous exécutez une commande qui ne se termine pas comme, elle ne reviendra pas, donc un argument mot-clé_pipeJ'ai besoin de vous dire ce qui se passe dans le pipeline.

>>> from sh import yes, tr
>>> it = tr(yes(), 'y','Y', _iter=True) #NG car la commande yes ne se termine pas
>>> it = tr(yes(_piped=True), 'y','Y', _iter=True) #C'est acceptable
>>> it.next()
u'Y\n'

Glob

Passer un astérisque comme argument de fonction ne le développe pas.

>>> from sh import ls
>>> ls('./*') #Parce qu'il ne sera pas déployé./*Les tentatives de recherche sont généralement infructueuses.

Utilisez sh.glob '' pour extraire. ** N'utilisez pas la bibliothèque standard `` glob.glob```. ** **

>>> from sh import ls, glob
>>> ls(glob('./*')) # sh.Développer à l'aide de glob

Exécution en arrière-plan

Par défaut, la fonction sh '' attend que le processus se termine. Si vous voulez l'exécuter en arrière-plan, ajoutez _bg = True``` à l'option. Vous pouvez attendre que le processus s'exécutant en arrière-plan se termine avec la méthode wait ''.

>>> from sh import sleep
>>> sleep(10)              #Bloquer pendant 10 secondes
>>> p = sleep(10, _bg=True) #Reviendra bientôt
>>> p.wait()               #Attendez la fin du processus

Code de fin et gestion des erreurs

Le code de fin de la commande peut être obtenu avec exit_code. S'il se termine normalement, il devient généralement 0.

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

Une exception est déclenchée si la commande se termine anormalement. Un code de fin spécifique peut être capturé avec ErrorReturnCode_ <end code> `` `. ErrorReturnCode``` capture tous les codes de terminaison.

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

Pour les commandes qui renvoient un code de fin différent de zéro même si la commande réussit, spécifiez une liste de codes de fin lorsque la commande réussit dans l'argument de mot-clé `` _ok_code```.

signal

Vous pouvez signaler le processus avec les trois méthodes suivantes.

Si le processus se termine par un signal, SignalException_ <numéro de signal> se produira lorsque waitest exécuté. De plus,exit_code``` est le numéro de signal négatif.

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

Comment ça fonctionne

Étant donné que les commandes externes pouvant être utilisées diffèrent en fonction de l'environnement, on peut voir que `` sh``` crée dynamiquement l'objet correspondant à la commande externe.

Le mécanisme d'importation de commandes arbitraires est à peu près implémenté dans le code suivant. Le fait est que lors de l'importation de modules, sys.modules [__ name __] '' est remplacé par une classe qui hérite de `` ModuleType```.

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)

Vous pouvez utiliser ce module pour importer et exécuter echo comme suit:

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

Matériel de référence

Recommended Posts

Traitez les commandes externes comme des fonctions avec sh
Script avec des commandes externes au pavé