如何在subprocess.call

时间:2016-01-22 22:29:30

标签: python subprocess

尝试打印没有12列的文件的文件名。

这适用于命令行:

for i in *dim*; do awk -F',' '{if (NR==1 && NF!=12)print FILENAME}' $i; done;

当我尝试在python脚本中将它嵌入subprocess.call时,它不起作用:

subprocess.call("""for %i in (*dim*.csv) do (awk -F, '{if ("NR==1 && NF!=12"^) {print FILENAME}}' %i)""", shell=True)

我收到的第一个错误是“此时打印意外”,所以我用Google搜索并在括号内添加^。下一个错误是“意外的换行符或字符串结束”,因此再次搜索并在NR == 1&& NF!= 12。使用当前代码,它在每个文件中打印了许多行,因此我怀疑if语句有问题。我在subprocess.call中以这种方式使用了awk和循环,但没有结合使用if语句。

1 个答案:

答案 0 :(得分:0)

AWK中的多个输入文件

在传递给subprocess.call()的字符串中,您的if语句正在评估字符串(可能不是您想要的比较)。通过在AWK中执行所有操作来简化shell命令可能更容易。您正在为shell的$i循环中的每个for执行AWK。由于您可以向AWK提供多个输入文件,因此实际上不需要此循环。

您可能希望扫描整个文件,直到找到任何行不超过12个字段,而不仅仅检查第一行(NR==1)。在这种情况下,条件仅为NF!=12

如果您只想检查每个文件的第一行,则在使用多个文件时NR==1会变为FNR==1NR是“记录数”(跨所有输入文件),FNR是当前输入文件的“记录文件数”。这些是AWK中的特殊内置变量。

此外,AWK的语法允许仅在行匹配某些条件时才执行块。没有条件(正如你所做的那样)为每一行运行块。例如,要扫描提供给AWK的所有文件并在第一行上打印除12个字段以外的文件的名称,请尝试:

    awk -F, 'FNR==1 && NF!=12{print FILENAME; nextfile}' *dim*.csv

我已将.csv添加到您的通配符*dim*中,就像在Python版本中一样。 -F,当然会将字段分隔符从默认空间更改为逗号。对于每个文件中的每一行,AWK检查字段NF的数量是否为12,如果不是,则执行代码块,否则它将继续执行下一行。此块打印AWK正在处理的当前文件的FILENAME,然后使用nextfile跳到下一个文件的开头。

尝试使用Python中的subprocess模块运行此AWK版本:

    subprocess.call("""awk -F, 'FNR==1 && NF!=12{print FILENAME; nextfile}' *dim*.csv""", shell=True)

三重引号使其成为文字字符串。 AWK的输出转到 stdout ,我假设您知道如何在Python中使用subprocess module

仅使用Python

不要忘记Python本身就是一种富有表现力和强大的语言。如果您已经在使用Python,那么使用 only Python 而不是混合使用Python,bash和AWK可能更简单,更容易,更轻松。

您可以找到文件的名称(从*dim*.csv中选择),每个文件的第一行包含12个以逗号分隔的字段:

import glob

files_found = []
for filename in glob.glob('*dim*.csv'):
    with open(filename, 'r') as f:
        firstline = f.readline()
        if len(firstline.split(',')) != 12:
            files_found.append(filename)
            f.close()

print(files_found)

glob module给出了与通配符模式*dim*.csv匹配的文件列表。读取每个文件的第一行并将其拆分为以逗号分隔的字段。如果这些字段的数量不是12,则会将其添加到列表files_found