将bash脚本转换为python而不使用子进程

时间:2015-01-09 23:57:24

标签: python bash awk sed subprocess

如何在不使用子进程命令

的情况下将以下内容转换为python
cat  $MYDIR/*  |grep ABCD |grep zip |grep -v idx |awk -F'/' '{print $3}'  |awk -F"_" '{print $2}'  |awk -F"." '{print $1}'  |sed 's/\$[A-Z]//g' |   sort|uniq  |egrep -v "^ABCD_G9" |egrep -v ABCD_00 |egrep -v "^ABCD_0[1-8]"  > $DATADIR/ABCDDataFile

1 个答案:

答案 0 :(得分:6)

您“分解”管道,了解每个部分的作用,然后在Python中重新编码每个部分,并根据需要进行连接。所以,让我们看看......:

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只需要各种“字段分隔符”.split以及结果列表的索引。

sort | uniq |

实际上最好翻译成单件:

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

(使用发生器与以前的情况保持一致)。

所以,一旦你翻译了每一篇文章,你就可以按照自己喜欢的方式连接它们。

连接的简单方法是通过函数调用,但这需要一些不自然的顺序,即最左边的部分(“source”,p1)成为深层嵌套调用的最内层参数。通过在交互式翻译提示符下进行import this,我们从其他智慧的角度中学习“扁平比嵌套更好”。

有点花哨(使用functools.partial在需要的地方预先绑定前导args,因此只留下只需要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典型的管道方法在操作上是最优的。但是,它可能非常有启发性,这就是为什么我花了一些时间在这里展示它!