Home > database >  How is the $@ array different from regular array
How is the $@ array different from regular array

Time:01-05

I wrote a function to check whether argument(s) was passed to script, so I had to create an alias variable for $@ because inside function that would be function's arguments. Here's the code:

script_args=$@

is_arg_passed() {
  local passed=false

  for passed_arg in ${script_args}; do
    for arg in "$@"; do
      if [[ "${passed_arg}" == "${arg}" ]]; then
        passed=true
        break
      fi
    done

    [[ "${passed}" == true ]] && break
  done

  echo "${passed}"
}

Though I definitely would like to learn how it can be implemented shorter, that's not the topic of my question (though some advice would be appreciated ;]).

My question is related to the for passed_arg in ${script_args}; do line:

Why does it not work when script_args expanded within string i.e. "${script_args}", when "${@}" or "$@" does. Only ${script_args} works.

So how is $@ different from the regular array (like (a b c)), and how is script_args different from $@? What is the catch?

CodePudding user response:

$@ is not an array, though it is array-like.

The assignment script_args=$@ simply creates a regular parameter whose value is the contents of $@ concatenated with a space. If you really want an array with the same contents, use

script_args=( "$@" )   # The quotes are critical!

is_arg_passed() {
  local passed=false

  for passed_arg in "${script_args[@]}"; do  # So are these quotes!
    for arg in "$@"; do
      if [[ "${passed_arg}" == "${arg}" ]]; then
        passed=true
        break
      fi
    done

    [[ "${passed}" == true ]] && break
  done

  echo "${passed}"
}

This kind of containment check can also be done using an associative array (as long as the arguments are not empty strings).

declare -A script_args
for arg; do
  # The value doesn't matter; we'll only be checking
  # if the key exists.
  script_args["$arg"]=
done

is_arg_passed() {
  for arg; do
    if ! [[ -v script_args[$arg] ]]; then
      echo false
      return 1
    fi
  done
  echo true
  return 0
}
    

CodePudding user response:

They're not different based on how you compare them because an array much like the positional parameters is expanded with a quote: "${script_args[@]}"

Also you're storing the arguments wrong. With script_args=$@ you store a string value to script_args. The value is a merged form of the values of $@ with the space used as a conjunctor.

To store them as an array, use script_name=("$@"). Read the Arrays section of the Bash manual to know more about it.

  •  Tags:  
  • Related