Bash. The fastest and most efficient array search

I need to search for an array so many times in a bash process. I need to know that this is the fastest and most effective way to do this. I know how to do this. The question is how to do this in the fastest way. Now I do this:

#!/bin/bash

array_test=("text1" "text2" "text3" "text4" "text5")
text_to_search="text4"

START=$(date +%s.%N)

for item in "${array_test[@]}"; do
    if [ ${item} = "${text_to_search}" ]; then
        echo "found!!"
        break
    fi
done

END=$(date +%s.%N)
DIFF=$(echo "$END - $START" | bc)
echo $DIFF

With this code we can measure time.

Imagine we have 300 elements or more in an array. Is there a faster way? I need to increase performance. Thank.

EDIT I am using bash 4.2. The real array has line breaks:

array_test=(
"text1"
"text2"
"text3"
"text4"
"text5"
)
+4
source share
4 answers

The fastest version (for large arrays)

Use grep -qFinarray[*]

if ( IFS=$'\n'; echo "${array[*]}" ) | grep -qFx "$text_to_search"; then
    echo "found!"
fi

: , .

, , bash. \x1E ( ASCII " " "), . :

export d=$'\x1E' # unused character, here "Record Seperator"
if ( IFS="$d"; echo "$d${array[*]}$d" ) | grep -qF "$d$text_to_search$d"; then
    echo "found!"
fi

1'000'000, :

size=$((10 ** 6))
array_test=($(seq -f 'text%.0f' 1 "$size"))

(: {1..1000000} , seq)

text_to_search="text$size"

  • grep -qF array[@] ( 3. . )
  • grep -qF array[*] (. )

:

  • 65,5
  • 59.3
  • 00.4 (, )
+2

, , (a) Bash , () . , , .

:

#!/bin/bash

declare -A array_test()
array_test=(["text1"]="" ["text2"]="" ["text3"]="" ["text4"]="" ["text5"]="")
text_to_search="text4"

if
  [[ ${array_test[$text_to_search]+found} ]]
then
  echo "Found!"
fi

, , ( , , ).

- . , , , Bash , , . , , .

, , , :

for key in "${!array[@]}"
do
  do_something_with_the key
done

, , , . :

declare -A array_test=()
while IFS= read -r key
do
  array_test[$key]=
done < <(command_with_output)

, , () , unset. , :

declare -A array_test=()
array_test[existing_key]=
echo ${array_test[existing_key]+found} # Echoes "found"
echo ${array_test[missing_key]+found}  # Echoes nothing

"${var+value}" , , , value, . set -u, .

+2

If none of your array elements contains spaces, you can use pattern matching

array_test=("text1" "text2" "text3" "text4" "text5")
text_to_search="text4"

[[ " ${array_test[*]} " == *"  $text_to_search "*]] && echo found || echo not found

Quotation marks and spaces are important here.

In bash, in square brackets [[ ]], an operator ==is a pattern matching , not just string equality.

+2
source

A specific example based on @Fred's helpful answer using an associative array:

script.sh

#!/bin/bash

read -a array_test <<< $(seq 1 10000)
text_to_search="9999"

function from_associative_array {
  declare -A array
  for constant in ${array_test[@]}
  do
      array[$constant]=1
  done
  [[ ${array[$text_to_search]} ]] && echo  "Found in associative array";
}

function from_indexed_array {
  for item in "${array_test[@]}"; do
      if [ ${item} = "${text_to_search}" ]; then
          echo "Found in indexed array"
          break
      fi
  done
}

time from_indexed_array
time from_associative_array

$ bash script.sh
Found in indexed array

real    0m0.611s
user    0m0.604s
sys     0m0.004s

Found in associative array

real    0m0.297s
user    0m0.296s
sys     0m0.000s
+1
source

Source: https://habr.com/ru/post/1670160/


All Articles