【问题标题】:How to check for global variables in source code using awk, sed or grep?如何使用 awk、sed 或 grep 检查源代码中的全局变量?
【发布时间】:2017-12-07 20:45:11
【问题描述】:

我需要针对 bash 脚本运行一系列 Python 源代码,该脚本包含检查全局变量是否存在的逻辑。我可以使用 2 个标准来查看变量是否是全局变量:

read file line by line
if there is an '=' (assignment sign) in the line AND no '#' in beginning of line (it is not commented out), check:
    is there a 'def' string anywhere in the text above this assignment line, e.g. def function_name()?
         if yes, variable within a function and hence not global
         else, possible global variable

如何使用grepawksed 实现此伪代码?我也愿意接受有关使用 bash 脚本查找全局变量的更好策略的建议。

示例代码:

int a = 23

def func_name():
    ...body...

此代码未通过我们的测试。

示例代码2:

def function_name():
    int a = 4
    ...

此代码通过测试。

【问题讨论】:

  • 添加了 2 个示例以使问题更具体。
  • 使用面向行的工具来分析 Python 源代码似乎是非常错误的,当有用 Python 编写的好的 Python 源代码分析器时。
  • 按照说明实现这个伪代码很简单:你需要一个触发器,它最初是假的,一旦你遇到def就设置为真,当你遇到结束时再次设置为假的功能。每当您看到= 并且触发器为假时,您将其视为全局变量。当然,真正的问题已经存在于伪代码中:它偶尔会报告正确的全局变量,但也会给出误报并错过一些全局变量。
  • 在不使用 python 的情况下考虑这种类型的事情很有趣,但如果您实际上是在实际安装了 python 的系统上解析已知安全的 python 代码,那也是不明智的。如果您不想运行代码(也许您是在网上找到的?)和/或本地没有安装 python,也许这是一个有趣的前提。看我的回答。

标签: bash shell awk sed grep


【解决方案1】:

我认为这不是一个好主意,但这是您的逻辑的文字实现:

awk -F= '
  /^[^#]/ && NF > 1 && saw_def { print "not global:", $0; next  }
  NF > 1 { print "possibly global:", $0 }
  { saw_def = /def/ }
' file.py

这告诉 awk 使用 = 作为四个 pattern {action} 对的字段分隔符:

  1. 行以非# 开头,有第二个字段(因此有一个=),并且设置了saw_def 变量:
    将该行打印为非全局赋值;继续下一行(停止模式匹配)
  2. 否则行有=
    将行打印为可能的全局分配
  3. (任何与#1 不匹配的行):
    saw_def 设置为表示行上是否存在“def”的布尔值

这是一个测试失败的例子:

def function_name():
    int a = 4
    int b = 8

您请求的逻辑将注意到 a 不是全局的,而 b 可能是全局的。


这样应该会更好:

awk '
  NF == 0 { next }
  {
    indent = match ($0, /[^ \t]/) - 1  # count of leading whitespace
    has_assign = /^[^#]*=/
  }
  $1 == "def" && !in_def { in_def = indent; next }
  indent > in_def && has_assign { print "not global:", $0; next }
  indent <= in_def { in_def = 0 }
  has_assign { print "possibly global:", $0 }
' file.py

这会尝试解析 python 代码,利用语言的强制缩进来跟踪您何时处于函数定义中。这五个pattern {action} 对是:

  1. 没有字段(空白行):
    跳到下一行
  2. (匹配任何其他行):
    indent设置为第一个之前的前导空格和制表符的数量
    has_assign设置为是否存在变量赋值(=存在于任何之前#)
  3. 第一个字段是“def”,我们还没有跟踪函数:
    使用 ind_def 跟踪当前缩进级别并停止匹配此行
  4. 我们缩进到足以在一个函数中并且我们有一个赋值:
    报告非全局变量赋值
  5. 缩进级别不超过最后一个函数:
    我们不再在函数中,请将函数缩进级别设置回零
  6. 我们有一个变量赋值(尚未触发 next):
    报告可能是全局变量赋值

注意,我不确定awk 的所有版本都理解\t,因此您可能需要一个文字标签来代替它。您可以在命令行中输入 Ctrl+v, Tab


我仍然认为自制的python解析器不是一个好主意。如果您确实在解析有效(并且已知安全)的 python 代码,this similar question 的答案实际上是 load 代码,这当然是确定的。如果您正在处理可能不安全的代码或类似 Python 的代码,并且/或者您正在使用的系统上缺少 Python 解释器,那么我的解决方案可能对快速代码审查很有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-11
    相关资源
    最近更新 更多