让我的awk shell脚本更有效率(解析python)



我最近的任务是审核我的团队在整个生产代码存储库中使用的所有 python 模块。

我想出了以下内容:

find ~/svn/ -name *.py 
| xargs grep -hn "^import|^from"
| awk -F ":" '{print $2}' 
| awk '{if (/from/) print $2; else {$1 = ""; print $0} }' 
| sed 's/,| /n/g' 
| sort 
| uniq > /tmp/pythonpkgs.txt 

按顺序,它

  • 查找所有 python 文件
  • 其中,以 importfrom 开头的行的 grep
  • 拆分:字符并使用以下内容,因此不包括文件名和输出编号
  • 如果行是形式from foo import bar,则打印foo,否则如果它是形式import foo打印foo
  • 将逗号和空格替换为换行符,例如 import a, b, c
  • 对输出进行排序并获取唯一

我自己把这个拼凑在一起,但我想它可能会更好。你会怎么做?巩固awk

一开始设置非常聪明,但有几个地方可以清理它:

1: find ~/svn/ -name *.py 
2: | xargs grep -hn "^import|^from"
3: | awk -F ":" '{print $2}' 
4: | awk '{if (/from/) print $2; else {$1 = ""; print $0} }' 
5: | sed 's/,| /n/g' 
6: | sort 
7: | uniq > /tmp/pythonpkgs.txt 

第 3 行:您不需要第一个 awk 拆分/打印 - 只需不要在 grep 上包含-n,这样您就不会在输出中包含行号。

time find ./<<my_large_project>> -name *.py 
| xargs grep -hn "^import|^from" 
| awk '{if (/from/) print $2; else {$1 = ""; print $0} }' 
| sed 's/,| /n/g' 
| sort 
| uniq
~~snip~~
real    0m0.492s
user    0m0.208s
sys     0m0.116s

第 6-7 行和第 4-5 行:如果有很多重复行,可以在运行awksed之前通过sort ing 和 uniq -ing 来加快执行速度

time find ./<<my_large_project>> -name *.py 
| xargs grep -hn "^import|^from" 
| sort 
| uniq 
| awk '{if (/from/) print $2; else {$1 = ""; print $0} }' 
| sed 's/,| /n/g'
~~snip~~
real    0m0.464s
user    0m0.224s
sys     0m0.140s

请注意,这将错过 PEP 0328 中所述的多行导入。 对这些导入的支持将使您的正则表达式搜索相对不平凡,因为您必须查找可选的括号并记下先前的空格。

特定构造的 greping 源代码非常脆弱,在许多情况下它可能会失败。例如,考虑:

import foo ; print 123

import foo, 
   bar

 str = '''
 import foo
 '''

等。

如果你对更健壮的方法感兴趣,这就是使用python自己的编译器可靠地解析导入名称的方法:

import ast
def list_imports(source):
    for node in ast.walk(ast.parse(source)):
        if isinstance(node, ast.Import):
            for name in node.names:
                yield name.name
        if isinstance(node, ast.ImportFrom):
            yield node.module

用法:

 for name in sorted(set(list_imports(some_source))):
     print name
这是我

的综合awk:

/^[ t]*import .* as/  {
    sub("^[ t]+","");          # remove leading whitespace
    sub("[ t]*#.*","");        # remove comments
    print $2;
    next;
}
/^[ t]*from (.*) import/ {
    sub("^[ t]+","");          # remove leading whitespace
    sub("[ t]*#.*","");        # remove comments
    print $2;
    next;
}
/^[ t]*import (.*)/  {
    sub("^[ t]+","");          # remove leading whitespace
    sub("[ t]*#.*","");        # remove comments
    split(substr($0,7),a,",");  # split on commas
    for (i=1;i<=length(a);i++) {
        gsub("[ t]+","",a[i]); # trim whitespace
        print a[i];
    }
    next;
}

通话方式:

find . -name '*.py' -exec awk -f scan.awk {} ; | sort | uniq

如前所述,它不会处理一些潜在的情况,例如用";"连接或用"\"拆分的行,或者用"()"分组,但它将涵盖大多数Python代码。

最新更新