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

时间:2015-01-21 15:37:57

标签: python bash shell awk

我最近负责审核我的团队在整个生产代码库中使用的所有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
  • 开头的行的greps
  • 拆分:字符并使用以下内容,因此不包含文件名和输出数
  • 如果该行的格式为from foo import bar,请打印foo,否则如果格式import foo打印foo
  • 使用换行符替换逗号和空格,用于import a, b, c
  • 等行
  • 排序输出并采用唯一身份

我自己一起攻击了这个,但我想它可能会更好。你会怎么做?合并awk s?

3 个答案:

答案 0 :(得分:2)

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

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行:如果你有很多重复的行,你可以在sortuniq之前加快执行速度,然后再运行{{1} }和awk

sed

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

答案 1 :(得分:2)

特定构造的grepping源代码非常脆弱,有很多情况可能会失败。例如,考虑一下:

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

答案 2 :(得分:0)

这是我整合的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代码。