【问题标题】:How to find minimum distance person name and corresponding distance using bash script?如何使用 bash 脚本查找最小距离人名和相应距离?
【发布时间】:2022-09-11 14:11:16
【问题描述】:

File 1 : sampleInputFile

Name, Xloc, YLoc, Zloc
John, 10.5, 80.1, 5.80
Mary, 30.4, 20.5, 9.20
Paul, 10, 1000.0, 10.6

File 2 : proj01.sh (bash script file)
File 3 : correspondingOutputFile (output would shown in this file)


If input cmd         : proj01.sh sampleInputFile 1   (In 3rd param, 1 is john, 2 is Mary, 3 is Paul)
Format of the output : Mary 62.9                     (as Mary is near to John, and we can round that to 63.0 also)

 **challenge** : 
1) Check if filename passed in 1st parameter exists, if not stop with some message.
2) check that the index passed in 2nd parameter is an integer and is valid, which means is it less or equally to the number of entries and > 0.
3) bash script (proj01.sh) is going to find the min dist from the index person to another person.
    calculate distances using :  d = sqrt ( (x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2 )

注意:所有文件都在同一个目录中。

试图读取值,但不确定如何通过给定的索引行比较所有行:

{
    read
    while IFS=, read -r n x y z
    do 
        echo "n: $n x: $x y: $y z: $z"
    done
} < $inputFile

我非常感谢任何形式的帮助。

【问题讨论】:

  • shell 不能进行任何浮点计算,因此您的脚本将需要使用像 awk 这样的外部工具,这意味着最好的方法是将整个逻辑编写在 awk 中,然后使用 shell 进行调用awk 一次

标签: linux bash ubuntu coordinates nearest-neighbor


【解决方案1】:

在这里,我使用 awk 执行计算,最后我将结果四舍五入,如你所说。 变量以字母“l”为前缀,意思是“本地范围”。

该函数接收数据文件和原始记录,使用与我们在数据文件中可以找到的相同格式(名称、x_loc、y_loc、z_loc)。

您需要创建更多代码来进行验证。我没有提供完整的代码,因为我知道你正在练习这个挑战。

这个函数会跳过与原点相同的记录,这样使用起来会更舒服:

######################################################################
# Finds the person with the shortest distance from a specified origin
# Arguments:
#  l_data_file - Data file to get the information
#  l_origin - Origin record. (Format: Mary, 30.4, 20.5, 9.20)
######################################################################
function finds_the_person_with_shortest_distance() {
  local l_data_file="$1"
  local l_origin_data="$2"

  local l_origin_name
  local l_origin_x_loc
  local l_origin_y_loc
  local l_origin_z_loc

  local l_name
  local l_x_loc
  local l_y_loc
  local l_z_loc

  local l_current_distance
  local l_min_distance
  local l_min_distance_person_name

  read l_origin_name l_origin_x_loc l_origin_y_loc l_origin_z_loc < <(echo "${l_origin_data}" | tr -d ',')

  local l_flag_first_record=true

  while read l_name l_x_loc l_y_loc l_z_loc ; do

    # Skips the first record
    if [[ "${l_flag_first_record}" == "true" ]]; then
      l_flag_first_record=false
      continue
    fi

    # Skips the person at the same location as the origin
    if [[ "${l_origin_name}" == "${l_name}" ]] &&
       [[ "${l_origin_x_loc}" == "${l_x_loc}" ]] &&
       [[ "${l_origin_y_loc}" == "${l_y_loc}" ]] &&
       [[ "${l_origin_z_loc}" == "${l_z_loc}" ]]; then
      continue
    fi

    ##### calculates the distance #####
    l_current_distance=$(
       echo "${l_origin_x_loc} ${l_origin_y_loc} ${l_origin_z_loc} ${l_x_loc} ${l_y_loc} ${l_z_loc}" | 
         awk '{ print int( sqrt( ($1-$4)^2 + ($2-$5)^2 + ($3-$6)^2 ) ) }'
    )

    if [[ -z "${l_min_distance}" ]] ||
       [[ ${l_current_distance} -lt ${l_min_distance} ]]; then
      l_min_distance=${l_current_distance}
      l_min_distance_person_name="${l_name}"
    fi

  done < <(cat "${l_data_file}" | tr -d ',')

  echo "${l_min_distance_person_name} ${l_min_distance}"
}

【讨论】: