awk 中的“inf”不像“-inf”那样工作

Ric*_*ian 8 awk text-processing

给定一个单列数字文件,调用它f,下面的 awk 代码将返回最大值

cat f | awk    '   BEGIN {max = -inf}
                       {if ($1>max) max=$1} 
                   END { print max }
               '
Run Code Online (Sandbox Code Playgroud)

获得最小值的相同方法不会产生任何结果

cat f | awk '
               BEGIN  {min = inf}
                  {if ($1<min) min=$1} 
               END {print min}
            '
Run Code Online (Sandbox Code Playgroud)

但是,如果不是使用inf,而是从 开始min = [some large number],如果数字足够大,取决于文件中的内容,则修改后的代码有效。

为什么不起作用inf,是否有某种方法可以使min案例像max案例一样工作,而不必知道文件中的内容?

Adm*_*Bee 16

实际工作最好由未初始化的最大/最小值,解决了一个假想的“最小”和“最大”号(这可能不是您所使用的框架来实现,在这种情况下awk),但是通过使用初始化它的实际数据. 这样,它始终可以保证提供有意义的结果。

在您的情况下,您可以使用您遇到的第一个值(即第一行中的条目)分别通过添加规则来初始化maxmin

NR==1{min=$1}
Run Code Online (Sandbox Code Playgroud)

到你的awk脚本。那么,如果第一个值已经是最小值,则后续的测试不会覆盖它,最终会产生正确的结果。这同样适用于最大值的搜索,因此在组合搜索中,您可以声明

NR==1{max=min=$1}
Run Code Online (Sandbox Code Playgroud)

至于为什么你的方法的原因inf没有工作,awk-inf似乎,@steeldriver已经提供了你的问题,我也总结了完整起见评论一个很好的解释:

  • 在 中awk,变量是“动态类型的”,即一切都可以是字符串或数字,具体取决于用途(但awk会“记住”上次使用的内容并保留该信息以供下次操作使用)。
  • 每当在代码中发现涉及变量的算术运算时,awk将尝试将该变量的内容解释为数字并执行运算,如果成功,则从该变量的位置将其键入为数字。
  • 任何尚未被赋值的变量的默认值是空字符串,在算术运算中被解释为 0。
  • 变量名称(*) inf在没有特殊的意义awk,因此,使用刚刚所以当,它是一个空的变量,将评估为0的运算式,例如-inf。因此,如果您的数据都是正数,则max初始化为变量的“最大搜索”-inf有效,因为-inf它只是 0(因此,最小的非负数)。
  • 然而,在“最小搜索”问题中,初始化mintoinf会将变量初始化为空字符串,因为不存在算术运算可以保证将该空字符串自动转换为数字。
  • 所以在后面的对比中

    NR==1{min=$1}
    
    Run Code Online (Sandbox Code Playgroud)

    输入, $1, 与字符串值进行比较,这就是为什么也awk将其$1视为字符串,并执行字典比较而不是数字比较的原因。

  • 但是,按字典顺序,没有什么比空字符串“更小”,因此min 永远不会被分配新值。因此,在该END部分中,声明

    NR==1{max=min=$1}
    
    Run Code Online (Sandbox Code Playgroud)

    打印(仍然)空字符串。

(*) 请参阅Stephen Kitt 的回答,了解带有内容的字符串"inf"如何在awk.


Ste*_*itt 13

您的方法不起作用,因为inf在默认非 POSIX 模式下在 GNU AWK 中没有特殊含义。结果,它被解释为变量名,并且由于变量没有被设置为任何东西,它的值在算术上下文中为 0,在字符串上下文中为空字符串。因此,您的代码只会在为正数时找到最大值(因为max在算术上下文中初始化),而不会找到最小值(因为min在字符串上下文中初始化);有关详细信息,请参阅AdminBee 的回答

要确定文件(或流)中的最小值和/或最大值,您应该遵循AdminBee's answer 中给出的建议。

但是,如果您使用的是 GNU AWK,则可以计算log(0)以使用正无穷大或负无穷大初始化变量,并以类似于您的方法的方式使用它:

BEGIN { max = log(0) }
$1 > max { max = $1 }
END { print max }
Run Code Online (Sandbox Code Playgroud)
BEGIN { min = -log(0) }
$1 < min { min = $1 }
END { print min}
Run Code Online (Sandbox Code Playgroud)

与从第一行初始化值相比,这种方法的唯一优点是,它在没有处理任何值时提供独特的结果——正无穷大或负无穷大最终是没有看到值的可靠指标。(还有其他方法可以确定这一点,包括在从第一行初始化时检查空字符串而不是 0。)

对于处于 POSIX 模式 ( POSIXLY_CORRECT=1) 的GNU AWK或其他符合 POSIX 的 AWK 解释器,例如mawk,在算术上下文中"inf"作为字符串提供会产生无穷大,这要归功于strtod

BEGIN { max = "-inf" + 0 }
$1 > max { max = $1 }
END { print max }
Run Code Online (Sandbox Code Playgroud)
BEGIN { min = "+inf" + 0 }
$1 < min { min = $1 }
END { print min}
Run Code Online (Sandbox Code Playgroud)