2

I have a string like this:

array_string="a b"

I have an array like this:

array=(a b c)

I want to verify that all the elements of array_string are included in array if so I can overwrite the array with the element included in the array_string:

array=($array_string)

Which is the best way to do such a validation?

4
  • There's no built-in operation for this. You'll need to convert array_string to an array, then use nested loops to test if they're all in array. Commented Sep 4, 2020 at 16:57
  • bash has no operator to test if a string is in an array. If you need complex array operations like this frequently, bash is not the right language to use. Commented Sep 4, 2020 at 16:58
  • Why is array_string expected to contain multiple words but stored in a variable? What if one of the word contains spaces? This design itself is flawed. You should be maintaining two separate arrays Commented Sep 4, 2020 at 17:56
  • @Inian the array string is passed as an environment variable. This is a requirement I can't change that Commented Sep 4, 2020 at 19:03

3 Answers 3

2

You may use grep with couple of process substitutions:

grep -qvf <(printf '%s\n' "${array[@]}") <(echo "${array_string// /$'\n'}") ||
echo "all elements of array_string are present in array"
Sign up to request clarification or add additional context in comments.

Comments

2

For string-to-array comparison the following example uses space as the separator and expects it to be at the start and end of the list so that every value will be wrapped between two separators. It also avoids using an external process or subshell.

for ((index=0; index < "$((${#array[@]}"; index++)); do
  if [[ "$array_string" != *" ${array[$index]} "* ]]; then
    return 1
  fi
done

For an array-to-array comparison it's easy to convert the string to an array after removing the leading separator, and then use a nested loop to compare them. This can also avoid using an external process or subshell as read is a bash builtin:

# Needs to read to a different variable so it
#   doesn't empty the source and read nothing.
IFS=' ' read -ra string_array <<< "${array_string# }"
found=1
for ((x=0; x < "${#string_array[@]}"; x++)); do
  for ((y=0; y < "${#array[@]}"; y++)); do
    if [[ "${string_array[$x]}" == "${array[$y]}" ]]; then
      found=0
    fi
  done

  if [[ found -ne 0 ]]; then
    return 1
  fi

  found=1
done

Comments

0

You can determine the items which exist in the array_string but don't exist in the array like this:

join -v1 <(sort -b <<< "${array_string// /$'\n'}") <(IFS=$'\n'; sort -b <<< "${array[*]}")

with the assumption that items don't contain spaces. Using this, you can do:

if [[ -z $(join -v1 <(sort -b <<< "${array_string// /$'\n'}") <(IFS=$'\n'; sort -b <<< "${array[*]}")) ]]
then
    echo "array_string is a subset of array"
else
    echo "array_string is NOT a subset of array"
fi

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.