用bash shell计算连续点的距离

时间:2019-03-29 07:13:20

标签: shell awk

我需要帮助! 我有几个要点ABCDEF ...的位置是这样的:

A  0.00  0.50  0.10
B  1.00  2.50  2.00
C  0.70  0.88  1.29
D  2.13  2.90  0.11
E  1.99  0.77  0.69
...

我的目的是计算AB,BC,CD,EF等的距离,并将它们的总和与如下形式的输出相加:

sum_distance(AB)
sum_distance(AB+BC)
sum_distance(AB+BC+CD)
sum_distance(AB+BC+CD+DE)
sum_distance(AB+BC+CD+DE+EF)
.... 

我在awk网上发现可以做到这一点,并适用于我的案子。但是,没有结果或错误导出到屏幕上。你能帮我解决这种情况吗?

bash shell,awk

awk 'FNR==NR { a[NR]=$0; next } { for (i=FNR+1;i<=NR-1;i++) {split(a[i],b); print $1 "-" b[1], sqrt(($2-b[2])^2 + ($3-b[3])^2 + ($4-b[4])^2) | "column -t" } NR--}'

输出:

2.934280150
4.728297987
7.470140434
9.682130488
11.92469598
......

3 个答案:

答案 0 :(得分:2)

对于此琐碎的任务,您不需要如此复杂的脚本。尝试以下方法:

awk 'NR>1{ printf "%.9f\n",s+=sqrt(($2-x)^2+($3-y)^2+($4-z)^2) }
{ x=$2;y=$3;z=$4 }' file

对于A以外的所有点,计算距离,将其加到总和s上并打印总和。对于所有点,将坐标保留在x, y, z中以进行下一步计算。其输出与gawk相似:

2.934280150
4.728297987
7.470140434
9.682130488

答案 1 :(得分:1)

尝试一下:

awk 'function d(a,b){split(a,x);split(b,y);return sqrt((x[2]-y[2])^2 + (x[3]-y[3])^2 + (x[4]-y[4])^2);} {p[FNR]=$0} FNR>1{sum[FNR]=sum[FNR-1]+d(p[FNR-1],p[FNR]);printf "%.9f\n",sum[FNR];}' file

具有file这样的内容:

A  0.00  0.50  0.10
B  1.00  2.50  2.00
C  0.70  0.88  1.29
D  2.13  2.90  0.11
E  1.99  0.77  0.69

将提供如下输出:

2.934280150
4.728297987
7.470140434
9.682130488

您没有提供点F,因此您的最后一行输出实际上不能在此处计算。

在此处输入几行:

awk '
function d(a,b){
    split(a,x);
    split(b,y);
    return sqrt((x[2]-y[2])^2 + (x[3]-y[3])^2 + (x[4]-y[4])^2);
} 
{p[FNR]=$0} 
FNR>1{
    sum[FNR]=sum[FNR-1]+d(p[FNR-1],p[FNR]);
    printf "%.9f\n",sum[FNR];
}' file

这里非常简单,功能d用于确定距离。并重用前一行的总和。

有趣的是,如果您要计算图形的总距离,请首先从一个点开始,然后逐渐将点添加到图形中。即:

sum_distance(AB)
sum_distance(AB+BC+AC)
sum_distance(AB+BC+AC+AD+BD+CD)
...

然后可以做一点改进,就像这样:

$ awk 'function d(a,b){split(a,x);split(b,y);return sqrt((x[2]-y[2])^2 + (x[3]-y[3])^2 + (x[4]-y[4])^2);} {p[FNR]=$0} FNR>1{sum[FNR]=sum[FNR-1];for(i=FNR-1;i>0;i--)sum[FNR]+=d(p[i],p[FNR]);printf "%.9f\n",sum[FNR];}' file
2.934280150
6.160254691
14.349070561
22.466306583

答案 2 :(得分:1)

什么是基本规则? (切勿在您不懂的互联网上使用代码...)

您尝试使用的awk脚本问题不完全是您的情况。通过设置FNR==NR,然后使用循环限制(i=FNR+1;i<=NR-1;i++),可以期待多个输入文件。对于您的情况,实际上可以通过完全删除循环来简化脚本,因为您只有一个输入文件。

您只需要保存第一行,然后使用next读取下一行,计算并输出前一行与当前行之间的距离,将当前行设置为a[]中的行数组并重复直到行用完,例如

awk '{
    a[NR]=$0
    if (NR == 1)
        next
    split(a[NR-1],b)
    printf "%s\t%s\n", b[1] "-" $1, 
        sqrt(($2-b[2])^2 + ($3-b[3])^2 + ($4-b[4])^2)
    a[NR]=$0
}'

示例输入文件

$ cat f
A  0.00  0.50  0.10
B  1.00  2.50  2.00
C  0.70  0.88  1.29
D  2.13  2.90  0.11
E  1.99  0.77  0.69

使用/输出示例

只需将脚本粘贴到终端中,然后在文件名末尾添加文件名,例如

$ awk '{
>     a[NR]=$0
>     if (NR == 1)
>         next
>     split(a[NR-1],b)
>     printf "%s\t%s\n", b[1] "-" $1,
>         sqrt(($2-b[2])^2 + ($3-b[3])^2 + ($4-b[4])^2)
>     a[NR]=$0
> }' f
A-B     2.93428
B-C     1.79402
C-D     2.74184
D-E     2.21199

仔细检查一下,如果还有其他问题,请告诉我。