Рассчитать расстояния непрерывной точки по оболочке bash - PullRequest
3 голосов
/ 29 марта 2019

Мне нужна помощь!У меня есть несколько точек 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 ]

2 голосов
/ 29 марта 2019

Вам не нужен такой сложный скрипт для этой тривиальной задачи. Попробуйте вместо этого:

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 голос
/ 29 марта 2019

Что такое кардинальное правило ? (никогда не используйте код из интернета, которого вы не понимаете ...)

Проблема со скриптом 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

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

1 голос
/ 29 марта 2019

Попробуйте:

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 для расстояния.И повторно использовать сумму прежней линии.

И для удовольствия, если вы хотите рассчитать общее расстояние графика, изначально с одной точкой и постепенно добавляйте точку на график.IE:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...