【问题标题】:Variable operator for numerical comparison in awk用于 awk 中数值比较的变量运算符
【发布时间】:2019-01-30 22:23:30
【问题描述】:

awk 可以使用变量运算符进行数值比较吗?以下代码适用于硬编码运算符,但不适用于变量运算符:

awk -v o="$operator" -v c="$comparison" '$1 o c'

【问题讨论】:

    标签: awk


    【解决方案1】:

    不,那行不通。 awk 的-v 选项定义了实际的 Awk 变量,而不是令牌级别的宏替换。

    它不起作用的原因与它不起作用的原因相同:

    awk 'BEGIN { o = "+"; print 2 o 2 }'  # hoping for 2 + 2
    

    Awk 不同于 POSIX shell 和类似的语言;它不会通过文本替换来评估变量。

    由于您是从 shell 命令行调用 Awk,您可以使用 shell 的替换来生成 Awk 语法,从而获得该效果:

    awk -v c="$comparison" "\$1 $operator c"
    

    我们现在需要在 $1 上加上反斜杠,因为我们切换到双引号,其中 $1 现在可以被 shell 本身识别。

    【讨论】:

    • 此时也不需要变量,也将其移到引号中。
    • @karakfa 在不知道comparison 的确切内容的情况下,我们无法拨打电话。考虑awk -v c='a"b' 'BEGIN { print c }'。如果我们将a"b 插入到Awk 脚本的主体中来代替c,即使我们把它放在引号中,也会产生语法错误。另一方面,$operator 在设计上可能是一个有效的 Awk 操作符标记。 -v 机制的存在是有原因的;它比在 Awk 语法中插入文本更健壮。
    【解决方案2】:

    Kaz 提出的另一种方法是定义您自己的映射函数,该函数将两个变量作为参数和相应的运算符字符串o

    awk -v o="$operator" -v c="$comparison" '
          function operator(arg1, arg2, op) {
              if (op == "==") return arg1 == arg2
              if (op == "!=") return arg1 != arg2
              if (op == "<") return arg1 < arg2 
              if (op == ">") return arg1 > arg2
              if (op == "<=") return arg1 <= arg2 
              if (op == ">=") return arg1 >= arg2 
          }
        { print operator($1,c,o) }'
    

    这样您还可以定义自己的运算符。

    【讨论】:

    • 我喜欢这个,它允许if (operator(a,op,b) { &lt;commands&gt; } - 非常灵活地选择每个字段的不同标准。
    【解决方案3】:

    不,但您有两个选择,最简单的方法是让 shell 扩展其中一个变量,使其成为 awk 脚本的一部分,然后再运行 awk:

    $ operator='>'; comparison='3'
    $ echo 5 | awk -v c="$comparison" '$1 '"$operator"' c'
    5
    

    否则你可以编写自己的eval风格函数,例如:

    $ cat tst.awk
    cmp($1,o,c)
    
    function cmp(x,y,z,      cmd,line,ret) {
        cmd = "awk \047BEGIN{print (" x " " y " " z ")}\047"
        if ( (cmd | getline line) > 0 ) {
            ret = line
        }
        close(cmd)
        return ret
    }
    
    $ echo 5 | awk -v c="$comparison" -v o="$operator" -f tst.awk
    5
    

    https://stackoverflow.com/a/54161251/1745001。即使您的 awk 程序保存在文件中,后者也可以工作,而前者不会。如果您想将函数库与命令行脚本混合使用,那么这是使用 GNU awk for -i 的一种方法:

    $ cat tst.awk
    function cmp(x,y,z,      cmd,line,ret) {
        cmd = "awk \047BEGIN{print (" x " " y " " z ")}\047"
        if ( (cmd | getline line) > 0 ) {
            ret = line
        }
        close(cmd)
        return ret
    }
    
    $ awk -v c="$comparison" -v o="$operator" -i tst.awk 'cmp($1,o,c)'
    5
    

    【讨论】:

      猜你喜欢
      • 2014-08-28
      • 2021-06-16
      • 1970-01-01
      • 2019-01-18
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-17
      相关资源
      最近更新 更多