将 bash 脚本转换为 python 不带子进程

convert bash script to python without subprocess

如何在不使用子进程命令的情况下将以下内容转换为 python

cat  $MYDIR/*  |grep ABCD |grep zip |grep -v idx |awk -F'/' '{print }'  |awk -F"_" '{print }'  |awk -F"." '{print }'  |sed 's/$[A-Z]//g' |   sort|uniq  |egrep -v "^ABCD_G9" |egrep -v ABCD_00 |egrep -v "^ABCD_0[1-8]"  > $DATADIR/ABCDDataFile

你 "decompose" 管道,了解每个部分的作用,然后在 Python 中重新编码每个部分,适当连接。那么,让我们看看...:[=​​31=]

cat  $MYDIR/*  |

这部分连接了位于环境变量 MYDIR 中的目录中的所有文件。所以这可能会被实现,例如(当然在正确导入之后)

def p1():
    filenames = glob.glob(os.environ['MYDIR'] +'/*')
    for filename in filenames:
        with open(filename) as f:
            for line in f:
                yield line

使用生成器模拟 shell 管道的缓冲同步性。

grep ABCD |

这部分接受行,只发出包含 'ABCD' 的行。例如

def grep(pattern, inseq):
    for line in inseq:
        if pattern in line: yield line

同样适用于

grep zip |

下一部分,

grep -v idx |

只需要对grep取反,所以:

def grepv(pattern, inseq):
    for line in inseq:
        if pattern not in line: yield line

等等。翻译 egrepsed 需要正则表达式,但在其他方面非常相似,所以我会把这些留给你;此处使用的 awk 只需要各种 "field separators" 的 .split 和结果列表的索引。

sort | uniq |

其实最好翻译成一篇:

def sortuniq(inseq):
    for line in sorted(set(inseq)): yield line

(使用生成器与前面的案例保持一致)。

所以,一旦你翻译了每一个片段,你就可以用你喜欢的任何方式连接它们。

连接的简单方法是通过函数调用,但这需要某种不自然的顺序,即最左边的部分("source"、p1)成为深层嵌套调用的最内层参数。通过在交互式解释器提示符下执行 import this,我们了解到 "flat is better than nested".

有点花哨(使用 functools.partial 在需要的地方预先绑定前导参数,从而只留下只接受 inseq 作为参数的过滤函数)可以走很长的路...:

def pipeline(source, *filters):
    curf = source
    for f in reversed(filters):
        curf = functools.partial(f, curf())
    for line in curf():
        yield line

并将结果写入某个文件,

with open(whatever, 'v') as f:
    f.writelines(
        pipeline(
            p1, 
            functools.partial(grep, 'ABCD'),
            functools.partial(grep, 'zip'),
    # etc, etc

我真的会这样编码吗?很可能不会——我会对整个管道试图做的事情进行逆向工程,而不是逐条进行,最后将它们全部连接起来。虽然 Python 是一种灵活的多范式语言,但使用它来严格模拟 shell 典型的管道方法在操作上 不是 最佳。然而,它可能很有启发性,这就是为什么我在这里花了一些篇幅来展示它!