如何检查bash数组中两个元素的顺序?

huangapple go评论46阅读模式
英文:

How to check order of two elements in bash array?

问题

如何在Bash中编写一个函数来检查某个元素one是否出现在另一个元素two之前(同时验证这两个元素都在数组中)?

你可以使用以下的Bash函数来实现这一功能:

check_element_order() {
  local array=("$@")  # 将传入的参数转换为数组
  local element_one="$1"
  local element_two="$2"
  local found_one=false
  local found_two=false

  for item in "${array[@]}"; do
    if [ "$item" = "$element_one" ]; then
      found_one=true
    elif [ "$item" = "$element_two" ]; then
      found_two=true
    fi

    if [ "$found_two" = true ] && [ "$found_one" = false ]; then
      echo "element_one occurs before element_two"
      return 0  # 返回成功状态码
    fi
  done

  if [ "$found_one" = true ] && [ "$found_two" = false ]; then
    echo "element_one occurs after element_two"
    return 0  # 返回成功状态码
  fi

  echo "element_one and element_two not found in the array"
  return 1  # 返回失败状态码
}

# 用法示例:
my_array=("one" "two" "three" "four")
check_element_order "two" "three" "${my_array[@]}"

这个函数首先将传入的参数转换为数组,然后遍历数组,查找元素one和元素two。如果找到元素two而没有找到元素one,则返回"element_one occurs before element_two"。如果找到元素one而没有找到元素two,则返回"element_one occurs after element_two"。如果两个元素都没有找到,返回"element_one and element_two not found in the array"。根据返回的状态码,你可以在调用该函数后进行进一步的处理。

英文:

Context

After having written a method that checks whether element element_one occurs before element element_two in a comma separated list (in string format in Bash), I am experiencing some difficulties in converting the code and tests into a function that:

  1. Verifies element element_one is in the bash array.
  2. Verifies element element_two is in the bash array.
  3. Verifies element element_one occurs before element element_two in the array.

Code

element_one_before_two_in_csv() {
  local elem_one
  elem_one="$1"
  local elem_two
  elem_two="$2"
  local csv_array
  csv_array="$3"

  IFS=, read -r -a arr <<<"${csv_array}"
  local found_one
  local found_two
  
  assert_csv_array_contains_element "$elem_one" "$csv_array"
  assert_csv_array_contains_element "$elem_two" "$csv_array"

  for item in "${arr[@]}"; do
    if [[ $elem_one == "$item" ]]; then
      found_one="FOUND"
    fi
    if [[ $elem_two == "$item" ]]; then
      found_two="FOUND"
    fi

    if [[ "$found_two" == "FOUND" ]] && [[ "$found_one" != "FOUND" ]]; then
      echo "AFTER"
      break
    elif [[ "$found_one" == "FOUND" ]] && [[ "$found_two" != "FOUND" ]]; then
      echo "BEFORE"
      break
    fi
  done
  
}

assert_csv_array_contains_element() {
  local elem_one
  elem_one="$1"
  local csv_array
  csv_array="$2"

  if [[ "$(csv_array_contains_element $elem_one $csv_array)" != "FOUND" ]]; then
      echo "Error, did not find element:$elem_one in: $csv_array"
      exit 6
  fi
}

csv_array_contains_element() {
  local elem_one
  elem_one="$1"
  local csv_array
  csv_array="$2"

  IFS=, read -r -a containing_arr <<<"${csv_array}"
  local found_one
  for item in "${containing_arr[@]}"; do
    if [[ "$elem_one" == "$item" ]]; then
      found_one="FOUND"
      echo "FOUND"
    fi
  done
  if [[ $found_one != "FOUND" ]]; then
      echo "NOTFOUND"
  fi
}

Tests

#!./test/libs/bats/bin/bats

load 'libs/bats-support/load'
load 'libs/bats-assert/load'

@test "element_one_before_two_in_csv returns BEFORE for correct found order." {
  source ./src/helper.sh
  
  # Run function that is tested.
  run element_one_before_two_in_csv "two" "three" "one,two,three,four"
  assert_output "BEFORE"
  
}

@test "element_one_before_two_in_csv returns AFTER for swithced order." {
  source ./src/helper.sh

  run element_one_before_two_in_csv "three" "two" "one,two,three,four"
  assert_output "AFTER"
}


@test "element_one_before_two_in_csv raises error if first element is missing." {
  source ./src/helper.sh

  run element_one_before_two_in_csv "banana" "two" "one,two,three,four"
  assert_failure
	assert_output -p "Error, did not find element:banana in: one,two,three,four"
}

@test "element_one_before_two_in_csv raises error if second element is missing." {
  source ./src/helper.sh

  run element_one_before_two_in_csv "four" "banana" "one,two,three,four"
  assert_failure
	assert_output -p "Error, did not find element:banana in: one,two,three,four"
}

Output

bats test
test_array_order.bats
✓ element_one_before_two_in_csv returns BEFORE for correct found order.
✓ element_one_before_two_in_csv returns AFTER for switched order.
✓ element_one_before_two_in_csv raises error if first element is missing.
✓ element_one_before_two_in_csv raises error if second element is missing.
4 tests, 0 failures

Question

Hence, I would like to ask:
*How can a function in bash check whether some element one occurs before some element two in a bash array (whilst verifying both elements one and two are in the array)?

答案1

得分: 1

Try bash-regexp:

$ arr=(one two)
$ [[ ${arr[@]} =~ one.*two ]] && echo ${BASH_REMATCH[@]}
one two

$ arr=(two one)
$ [[ ${arr[@]} =~ one.*two ]] && echo ${BASH_REMATCH[@]}
英文:

Try bash-regexp:

$ arr=(one two)
$ [[ ${arr[@]} =~ one.*two ]] && echo ${BASH_REMATCH[@]}
one two
$ arr=(two one)
$ [[ ${arr[@]} =~ one.*two ]] && echo ${BASH_REMATCH[@]}

huangapple
  • 本文由 发表于 2023年2月13日 23:36:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/75438051.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定