【问题标题】:awk for loop does not set array index to correct valueawk for 循环未将数组索引设置为正确的值
【发布时间】:2021-05-23 13:00:39
【问题描述】:

我有这个小型地理位置数据集。

37.9636140,23.7261360
37.9440840,23.7001760
37.9637190,23.7258230
37.9901450,23.7298770

来自随机位置。 比如这个37.97570, 23.66721 我需要使用 awk 创建一个 bash 命令,该命令以简单的欧几里得距离返回距离。 这是我使用的命令

awk -v OFMT=%.17g -F',' -v long=37.97570 -v lat=23.66721 '{for (i=1;i<=NR;i++) distances[i]=sqrt(($1 - long)^2 + ($2 - lat)^2 ); a[i]=$1; b[i]=$2} END {for (i in distances) print distances[i], a[i], b[i]}' filename

当我运行这个命令时,我得到了这个不正确的奇怪结果,有人可以向我解释我做错了什么吗?

➜ awk -v OFMT=%.17g -F',' -v long=37.97570 -v lat=23.66721 '{for (i=1;i<=NR;i++) distances[i]=sqrt(($1 - long)^2 + ($2 - lat)^2 ); a[i]=$1; b[i]=$2} END {for (i in distances) print distances[i], a[i], b[i]}' filename                     

44,746962127881936 37.9440840 23.7001760
44,746962127881936 37.9901450 23.7298770
44,746962127881936 37.9636140 23.7261360
44,746962127881936  
44,746962127881936 37.9637190 23.7258230

已更新。

附加了@jas 提供的命令,我将od -c 包含为@mark-fuso suggetsted。

现在的问题是我从@jas 得到不同的结果

展示新问题的命令输出。

awk -v OFMT=%.17g -F, -v long=37.97570 -v lat=23.66721 '
{distance=sqrt(($1 - long)^2 + ($2 - lat)^2 ); print distance, $1, $2}
' file        
1,1820150904705098 37.9636140 23.7261360
1,1820150904705098 37.9440840 23.7001760
1,1820150904705098 37.9637190 23.7258230
1,1820150904705098 37.9901450 23.7298770

od -c 显示输入文件的内容。

od -c file
0000000   3   7   .   9   6   3   6   1   4   0   ,   2   3   .   7   2
0000020   6   1   3   6   0  \n   3   7   .   9   4   4   0   8   4   0
0000040   ,   2   3   .   7   0   0   1   7   6   0  \n   3   7   .   9
0000060   6   3   7   1   9   0   ,   2   3   .   7   2   5   8   2   3
0000100   0  \n   3   7   .   9   9   0   1   4   5   0   ,   2   3   .
0000120   7   2   9   8   7   7   0  \n
0000130

【问题讨论】:

  • for (i=1;i&lt;=NR;i++) 替换为i=NR;
  • @M.NejatAydin 问题与我已回复答案的评论部分相同。
  • 我得到了与答案中相同的输出。我无法重现你得到的输出。
  • 语言环境设置可能有问题吗?我看到你打印距离时得到的是逗号而不是小数点。
  • 我建议的唯一编辑是对 input 文件运行 od -c ...不需要 od -c 对来自 awk 的输出运行重点是看看awk 的内容是什么;而且由于我无权访问您的特定输入文件...您需要进行编辑...您的电话

标签: arrays linux for-loop awk settings


【解决方案1】:

虽然@jas 已经为这个问题提供了一个“修复”,但我想我会抛出一些关于 OP 的代码在做什么的问题......

一些基础知识...

  • awk 程序 ({for (i=1;i&lt;=NR;i++) ... ; b[i]=$2}) 应用于输入文件的每一行
  • 从输入文件中读取每一行时,awk 变量 NR 会跟踪行号(即,NR=1 用于第一行,NR=2 用于第二行,等等)
  • 在最后一次通过for 循环时,计数器(在这种情况下为i)将具有NR+1 的值(即,i++ 在最后一次通过循环时应用,从而留下@ 987654331@)
  • 除非对每一行输入进行条件检查,否则awk 程序将对输入文件中的每一行应用(包括空行 - 更多内容见下文)
  • for (i in distances)... 不保证按数字顺序处理数组索引

awk/for 循环正在执行以下操作:

  • 对于第一个输入行 (NR=1),我们得到 for (i=1;i&lt;=1;i++) ...
  • 对于第二个输入行 (NR=2),我们得到 for (i=1;i&lt;=2;i++) ...
  • 对于第 3 个输入行 (NR=3),我们得到 for (i=1;i&lt;=3;i++) ...
  • 对于第 4 个输入行 (NR=4),我们得到 for (i=1;i&lt;=4;i++) ...

对于awk 处理的每一行,程序将覆盖distance[] 数组中的所有先前条目;最终结果是最后一行 (NR=4) 将在 distance[] 数组的所有 4 个条目中放置相同的值。

a[i]=$1; b[i]=$2 数组分配发生在for 循环范围之外,因此每个输入行将分配一次(即不会被覆盖)但是,数组分配是使用i=NR+1 进行的;最终结果是第一行 (NR=1) 的内容存储在数组条目 a[2]b[2] 中,第二行 (NR=2) 的内容存储在数组条目 a[3]a[3] 中等。

使用 print i, distances[i], a[i], b[i]} 修改 OP 的代码并针对我得到的 4 行输入文件运行:

1 0.064310270672728084                            # no data for 2nd/3rd columns because a[1] and b[1] are never set
2 0.064310270672728084 37.9636140 23.7261360      # 2nd/3rd columns are from 1st row of input
3 0.064310270672728084 37.9440840 23.7001760      # 2nd/3rd columns are from 2nd row of input
4 0.064310270672728084 37.9637190 23.7258230      # 2nd/3rd columns are from 3rd row of input

由此我们可以看到输出的第一列是相同的(即distance[1]=distance[2]=distance[3]=distance[4]),而第二列和第三列与输入列相同除了它们被“向下移动” ' 一行。

这给我们留下了两个悬而未决的问题......

  • 为什么 OP 显示 5 行输出?
  • 为什么第一列是垃圾44,746962127881936

我能够通过在我的输入文件末尾添加一个空行来重现此问题:

$ cat geo.dat
37.9636140,23.7261360
37.9440840,23.7001760
37.9637190,23.7258230
37.9901450,23.7298770
                           <<=== blank line !!

使用 OP 的 awk 代码生成以下内容:

44.746962127881936
44.746962127881936 37.9636140 23.7261360
44.746962127881936 37.9440840 23.7001760
44.746962127881936 37.9637190 23.7258230
44.746962127881936 37.9901450 23.7298770

注意事项

  • 此顺序与 OP 的示例输出不同,可能是由于 OP 的 awk 版本未按数字顺序处理 for (i in distances)...; OP 可以尝试for (i=1;i&lt;=NR;i++)...for (i=1;i in distances; i++)... 之类的方法(尽管后者不适用于人口稀少的数组)
  • OPs 输出(在问题中;在对@jas 答案的评论中)显示逗号(,)代替第一列的句点(.)所以我猜 OP 的 env 正在使用将逗号/句点切换为千位/小数分隔符的语言环境(尽管输入数据基于“相反”语言环境)

请注意,我们终于可以看到来自第 4 行输入的数据(“下移”并显示在第 5 行),但第一列的值似乎是无意义的……可以追溯到应用以下内容对空行:

sqrt(($1 - long)^2     + ($2 - lat)^2     )
sqrt((   - long)^2     + (   - lat)^2     )  # empty line => $1 = $2 = undefined/empty
sqrt((   - 37.97570)^2 + (   - 23.66721^2 )  
sqrt( 1442.153790      +    560.136829    )
sqrt( 2002.290619                         )
44.746952...                                 # contents of 1st column 

要“修复”此问题,OP 可以 a) 从输入文件中删除空白行或 b)awk 脚本添加一些逻辑以仅当输入行在字段#1 和#2 中具有(数字)值时才执行计算(即$1$2 不为空);由编码人员决定应用多少验证(例如,字段是否为数字,字段是否在合法 long/lat 值的范围内,等等)。


最后一个与设计相关的评论...如 jas 的回答所示,当所有所需的输出可以在处理时“即时”生成时,不需要任何数组(这反过来会减少内存使用)输入文件的每一行。

【讨论】:

    【解决方案2】:

    Awk 会为您处理循环。输入文件的每一行代码都会依次运行:

    $ awk -v OFMT=%.17g -F, -v long=37.97570 -v lat=23.66721 '
    {distance=sqrt(($1 - long)^2 + ($2 - lat)^2 ); print distance, $1, $2}
    ' file
    0.060152679674309095 37.9636140 23.7261360
    0.045676346307474212 37.9440840 23.7001760
    0.059824979147508742 37.9637190 23.7258230
    0.064310270672728084 37.9901450 23.7298770
    

    编辑: OP得到不同的结果。我注意到在 OP 的输出中打印distance 时有逗号而不是小数点。这表明区域设置可能存在问题。

    OP 确认语言环境设置为希腊语,导致输出不同。

    【讨论】:

    • 这对我来说不会产生相同的结果。 ➜ awk -v OFMT=%.17g -F, -v long=37.97570 -v lat=23.66721 ' {distance=sqrt(($1 - long)^2 + ($2 - lat)^2 ); print distance, $1, $2} ' filename 1,1820150904705098 37.9636140 23.7261360 1,1820150904705098 37.9440840 23.7001760 1,1820150904705098 37.9637190 23.7258230 1,1820150904705098 37.9901450 23.7298770
    • @panoskarajohn 我得到了与 jas 相同的输出,所以我想知道您的数据文件中 究竟是什么;如果您仍然遇到问题,我建议您更新问题以包含来自od -c filename 的完整输出;
    • @markp-fuso 我更新了我的问题,所以你可以看到od -c 输出
    • 这似乎是一个设置问题,我的 ubuntu 机器上有希腊设置。一旦将此作为额外信息附加到答案中,我将将此答案标记为已接受。
    • 好消息!已更新。
    猜你喜欢
    • 1970-01-01
    • 2021-05-28
    • 2022-01-22
    • 2021-05-27
    • 2015-09-22
    • 1970-01-01
    • 1970-01-01
    • 2020-11-20
    • 1970-01-01
    相关资源
    最近更新 更多