もた日記

くだらないことを真面目にやる

Pythonメモ : 「sh」パッケージでコマンド実行

sh


Pythonでコマンドを実行する場合は以下のようにsubprocessを使う方法があるが、shパッケージというものがあったので試してみる(標準ライブラリではないので使う際は注意)。

import subprocess
subprocess.run(["ls", "-l"]) # runはPython 3.5から

github.com

>>> from sh import ls
>>> print(ls())
CHANGELOG.md  README.rst    logo-big.png	   setup.cfg  test.py
LICENSE.txt   __pycache__   requirements-dev.txt   setup.py
MANIFEST.in   logo-230.png  requirements-docs.txt  sh.py


インストー


pipでインストールできるので下記コマンドを実行。shPython 2.6〜python 3.6で動作するようだ。

$ pip install sh


基本的な使い方


ドキュメントは下記リンクを参照。
1.12.13 — sh 1.12.13 documentation

以下のようにインポートすれば$PATHにあるコマンドを関数のように扱える。

from sh import ls
ls()

または

import sh
sh.ls()


引数を渡す


オプションの引数はカンマで区切って渡す。

sh.ls("-l", "/tmp", color="never")

または

sh.ls("-l", "/tmp", "--color=never")


パイプ


下記コマンドを実行したい場合は、

ls -1 | wc -l

最初に実行するコマンドを内側に置く。

sh.wc(sh.ls("-1"), "-l")


リダイレクト


STDOUT, STDERRが_out, _errという引数に対応しているので以下のように実行する。

sh.ls(_out="/tmp/out.txt")

または

with open("/tmp/out.txt", "w") as h:
    sh.ls(_out=h)


終了コードと例外


正常終了した場合の終了コードは0になる。

output = ls("/")
print(output.exit_code) # should be 0

異常がある場合は例外が発生する。

try:
    print(ls("/some/non-existant/folder"))
except ErrorReturnCode_2:
    print("folder doesn't exist!")
    create_the_folder()
except ErrorReturnCode:
    print("unknown error")


バックグラウンドプロセス


バッググラウンドで実行する場合は_bg=Trueを追加する。

from sh import sleep
# sleepが終わるまで待つ
sleep(3)
print("...3 seconds later")

# バックグラウンド
p = sleep(3, _bg=True)
print("prints immediately!")
p.wait()
print("...and 3 seconds later")


サブコマンド


gitのサブコマンドのようなものは以下のように実行する。

sh.git("show", "HEAD")
sh.git.show("HEAD")


その他


sudoもできるし、リアルタイムでtail -fみたいなこともできる(参考ドキュメント)。

from sh import tail

for line in tail("-f", "info.log", _iter=True):
    if "ERROR" in line:
        send_an_email_to_support(line)