介绍
很多人讨厌bash脚本。每当我要做最简单的事情时,我都必须查阅文档。如何将函数的参数转发给子命令?如何将字符串分配给变量,然后作为命令调用该字符串?如何检查两个字符串变量是否相等?如何分割字符串并获得后半部分?等等。不是我找不到这些答案,而是每次都必须查找它们。
但是,我们不能否认将整个程序当作纯粹的功能发挥作用的能力,以及将一个程序的输出传递到另一个程序的自然程度。因此,我想知道,我们能否将bash的某些功能与Python结合起来?
基础知识
让我们从一个类开始。这是一个简单的方法,将其初始化参数保存到局部变量,然后使用subprocess.run
对其自身进行延迟求值并保存结果。
import subprocess
class PipePy:
def __init__(self, *args):
self._args = args
self._result = None
def _evaluate(self):
if self._result is not None:
return
self._result = subprocess.run(self._args,
capture_output=True,
text=True)
@property
def returncode(self):
self._evaluate()
return self._result.returncode
@property
def stdout(self):
self._evaluate()
return self._result.stdout
def __str__(self):
return self.stdout
@property
def stderr(self):
self._evaluate()
return self._result.stderr
我们让它旋转一下:
ls = PipePy('ls')
ls_l = PipePy('ls', '-l')
print(ls)
# <<< files.txt
# ... main.py
# ... tags
print(ls_l)
# <<< total 16
# ... -rw-r--r-- 1 kbairak kbairak 125 Jan 22 08:53 files.txt
# ... -rw-r--r-- 1 kbairak kbairak 5425 Feb 1 21:54 main.py
# ... -rw-r--r-- 1 kbairak kbairak 1838 Feb 1 21:54 tags
使其看起来更像“命令式”
不用每次我们要自定义命令时都去调用PipePy。
ls_l = PipePy('ls', '-l')
print(ls_l)
相当于
ls = PipePy('ls')
print(ls('-l'))
换句话说,我们要使:
PipePy('ls', '-l')
相当于
PipePy('ls')('-l')
值得庆幸的是,我们的类创建了惰性对象这一事实在很大程度上帮助了我们:
class PipePy:
# __init__, etc
def __call__(self, *args):
args = self._args + args
return self.__class__(*args)
ls = PipePy('ls')
print(ls('-l'))
# <<< total 16
# ... -rw-r--r-- 1 kbairak kbairak 125 Jan 22 08:53 files.txt
# ... -rw-r--r-- 1 kbairak kbairak 5425 Feb 1 21:54 main.py
# ... -rw-r--r-- 1 kbairak kbairak 1838 Feb 1 21:54 tags
关键字参数
如果要向ls
传递更多参数,则可能会遇到--sort = size
。我们可以轻松地执行ls('-l','--sort = size')
。我们可以做得更好吗?
class PipePy:
- def __init__(self, *args):
+ def __init__(self, *args, **kwargs):
self._args = args
+ self._kwargs = kwargs
self._result = None
def _evaluate(self):
if self._result is not None:
return
- self._result = subprocess.run(self._args,
+ self._result = subprocess.run(self._convert_args(),
capture_output=True,