Francis Nickels
Francis Nickels

Reputation: 149

How can you tokenize a bash string into an array when the string includes a * character?

I have long used code similar to :

string="abc 123 xyz"
fields=( ${string} )
echo "The 3rd field = ${fields[2]}"

to break a string into fields and reference a particular element within the string.

But I ran into a strange use case today where the source string contained an '*' asterisks character. ie:

string="abc * xyz"
fields=( ${string} )
echo "The 3rd field = ${fields[2]}"
declare -p fields

In this case, the '*' does not map into the array literally, rather it appears to get expanded to a list of environment variables, and the array ends up with a much larger list or values that do not represent the original string.

Three questions:

  1. What exactly is * being expanded to?
  2. Can this expansion be disabled so the code will behave in the intended fashion?
  3. Is there a better way to accomplish the transformation of a string into an array of tokens that do not suffer from this side effect?

Upvotes: 0

Views: 45

Answers (2)

Eran Ben-Natan
Eran Ben-Natan

Reputation: 2615

    • is expanded to all the files in current dir, same as ls *
  1. Use single quote. {string="abc '*' xyz"}
  2. Maybe, but this is the good way :-)

Upvotes: 0

chepner
chepner

Reputation: 531718

Let read do it; unquoted parameter expansions are subject to pathname expansion as well as word splitting, so * is expanded to all file names in the current working directory.

read -a fields <<< "$string"

Alternatively, pathname expansion can also be disabled, allowing

set -f
fields=( $string )
set +f

Upvotes: 2

Related Questions