首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在awk中的'inf‘不是这样的'-inf’

在awk中的'inf‘不是这样的'-inf’
EN

Unix & Linux用户
提问于 2020-05-04 14:14:22
回答 3查看 1.8K关注 0票数 8

给定一个数字列文件,称为f,下面的Awk代码将返回最大值

代码语言:javascript
复制
cat f | awk    '   BEGIN {max = -inf}
                       {if ($1>max) max=$1} 
                   END { print max }
               '

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

代码语言:javascript
复制
cat f | awk '
               BEGIN  {min = inf}
                  {if ($1

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

为什么inf不能工作,并且有什么方法可以使min案例像max案例那样工作,而不需要知道文件中有什么?

EN

回答 3

Unix & Linux用户

回答已采纳

发布于 2020-05-04 15:09:10

<#>实际<#><#>任务最好通过初始化您的最大值/min值来解决,而不是通过假想的“最小”或“最大”数字来解决(在本例中,这个值可能不是在您正在使用的框架中实现),而是通过使用实际数据来初始化它。这样,它总是保证提供一个有意义的结果。

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

代码语言:javascript
复制
NR==1{min=$1}

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

代码语言:javascript
复制
NR==1{max=min=$1}

As是因为您使用 inf <#><#>的方法没有在awk上工作,而-inf似乎在评论您的问题时给出了一个很好的解释,为了完整起见,我也将对此进行总结:

  • awk中,变量是“动态类型的”,也就是说,根据使用情况,所有变量都可以是字符串或数字(但awk会“记住”上次使用的内容,并将该信息保留在下一次操作中使用)。
  • 每当在代码中找到涉及变量的算术操作时,awk将尝试将该变量的内容解释为一个数字,并执行操作,如果成功,则从该变量中键入数字。
  • 任何尚未被赋值的变量的默认值是空字符串,它在算术操作中被解释为0。
  • 变量名称(*) infawk中没有特殊意义,因此在使用时,它是一个空变量,它将在算术表达式(如-inf )中计算为0。因此,如果数据都是正的,那么初始化为max变量为-inf的“最大搜索”可以工作,因为-inf只是0(因此,最小的非负数)。
  • 但是,在“最小搜索”问题中,将min初始化为inf将变量初始化为空字符串,因为不存在需要将空字符串自动转换为数字的算术操作。
  • 因此,在后面的比较中,if ($1$1与字符串值进行比较,这就是为什么awk也将$1视为字符串,并执行字典比较而不是数字比较。
  • 但是,从词典的角度来看,没有什么比空字符串更“小”了,因此min从未得到新的值。因此,在END部分中,语句prints打印(仍然)空字符串。

(*)参见斯蒂芬·凯特的回答中的"inf"内容字符串在awk中的实际意义。

票数 19
EN

Unix & Linux用户

发布于 2020-05-04 15:15:38

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

要确定文件(或流)中的最小值和/或最大值,应遵循行政蜜蜂的回答中提供的建议。

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

代码语言:javascript
复制
BEGIN { max = log(0) }
$1 > max { max = $1 }
END { print max }
代码语言:javascript
复制
BEGIN { min = -log(0) }
$1 < min { min = $1 }
END { print min}

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

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

代码语言:javascript
复制
BEGIN { max = "-inf" + 0 }
$1 > max { max = $1 }
END { print max }
代码语言:javascript
复制
BEGIN { min = "+inf" + 0 }
$1 < min { min = $1 }
END { print min}
票数 13
EN

Unix & Linux用户

发布于 2020-05-05 21:28:12

实际上,存在三个无穷大的值:-inf +infinf,为了增加问题的复杂性,在awk中有引用和未引用的代码常量。

为了说明我的意思,请尝试如下( awk 4.2.1 (当前Debian 10)中的shell代码):

代码语言:javascript
复制
for cmd in original-awk "busybox awk" mawk nawk awk; do
    printf '%-6.5s' "$cmd"
    $cmd 'BEGIN {
        a="-inf";b="+inf";c="inf";
        d= -inf ;e= +inf; f= inf;
        printf "-∞%4s%4s +∞%4s%4s ∞%4s%4s | -∞%4s%4s +∞%4s%4s ∞%4s%4s\n",a,a+0,b,b+0,c,c+0,d,d+0,e,e+0,f,f+0}
    ' file

得到:

代码语言:javascript
复制
bawk  -∞-inf-inf +∞+inf inf ∞ inf inf | -∞   0   0 +∞       0 ∞       0
busyb -∞-inf-inf +∞+inf inf ∞ inf inf | -∞   0   0 +∞   0   0 ∞       0
mawk  -∞-inf-inf +∞+inf inf ∞ inf inf | -∞   0   0 +∞   0   0 ∞       0
nawk  -∞-inf-inf +∞+inf inf ∞ inf   0 | -∞   0   0 +∞   0   0 ∞       0
gawk  -∞-inf-inf +∞+inf inf ∞ inf   0 | -∞   0   0 +∞   0   0 ∞       0

该表列出了引用和未引用的变量赋值(abcdef)。对于每一种情况,由awk读取并转换为number (var+0)的值。

这意味着,即使在数字、"-inf"被转换为数字inf (没有符号)时,"inf"仍然保持不变,引用的D8可能会根据实现(在nawk和gawk中为0)变成inf0

当没有引号时,-inf+inf都变成0 (除了在bawk中,+∞被理解为空字符串"“并转换为0)。

奇怪的是,当没有引用时,所有inf都被解释为空字符串。

但所有未引用的-inf+infinf在用作var+0时都变为0。

因此,对于您想要做的事情,您需要引用"-inf""+inf",而不是inf

代码语言:javascript
复制
cat file | awk  '  BEGIN { max = "-inf"+0; min = "+inf"+0 }
                         { if ($1>max) max=$1
                           if ($1

也许,一种更容易(而不是portable0 )理解它的方法是执行:

代码语言:javascript
复制
gawk 'BEGIN{
               a="-inf";b="+inf";c="inf";
               d= -inf ;e= +inf; f= inf;

               print a,   typeof(a),   b,   typeof(b),   c,   typeof(c)
               print a+0, typeof(a+0), b+0, typeof(b+0), c+0, typeof(c+0)

               print d,typeof(d),e,typeof(e),f,typeof(f)
               print d+0,typeof(d+0),e+0,typeof(e+0),f+0,typeof(f+0)
      }'

它将打印:

代码语言:javascript
复制
-inf string +inf string inf string
-inf number inf number 0 number
0 number 0 number  unassigned
0 number 0 number 0 number

当然,正确和可移植的解决方案是从一开始就给max和min变量赋值:

代码语言:javascript
复制
cat file | awk  '  NR==1 { min = max = $1 }
                         { if ($1>max) max=$1
                           if ($1

-

描述从awk手册上是:

  • 有了--posix命令行选项,gawk就变成了“放手”。字符串值直接传递给系统库的strtod()函数,如果它成功地返回一个数值,则使用该值。根据定义,结果不能跨不同系统移植。它们也有点令人惊讶:

$ -| inf $ echo 0xDeadBeef gawk --posix '{打印$1 +0 }‘-| 3735928559

  • 如果没有--posix,gawk将特别解释四个字符串值‘+inf’、‘-inf’、‘+nan’和‘-nan’,从而生成相应的特殊数值。前导符号向gawk (和用户)传递一个信号,表示该值实际上是数字的。不支持十六进制浮点数(除非您也使用--非十进制数据,这是不推荐的)。例如:

$ echo nanny gawk '{ print $1 +0 }‘-| 0$ echo +nan gawk '{ print $1 +0 }’-| +nan $ 0xDeadBeef颇具gawk '{ print $1 +0 }‘-| 0 gawk忽略四个特殊值中的大小写。因此,‘+NaN’和‘+NaN’是相同的。除了处理输入,gawk还需要在输出值为NaN或无穷大时打印“正确”值。从4.2.2版本开始,对于这些值,gawk打印了刚才描述的四个字符串中的一个:‘+inf’、‘-inf’、‘+nan’或‘-nan’。类似地,在POSIX模式下,gawk使用值的%g格式字符串打印系统的C printf()函数的结果,不管是什么。

票数 3
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/584421

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档