Bash string to array with IFS

39,596

Solution 1

It does work, but it's unnecessary anyway because space is guaranteed to be in IFS by default. Don't set it manually. Doing so can cause problems.

Basically, never use word-splitting in Bash. Sometimes it's required to bite the bullet and use it if restricted to POSIX sh, if used very carefully. If you're going to set IFS, set it in the environment of one of the few commands where it has some effect, or at the very most, locally to a function.

You'll never need to use this so I won't explain everything:

$ printf -v str '%s ' Jun{01..10}
$ set -f
$ IFS=' ' declare -a 'arr=($str)'
$ declare -p arr
declare -a arr='([0]="Jun01" [1]="Jun02" [2]="Jun03" [3]="Jun04" [4]="Jun05" [5]="Jun06" [6]="Jun07" [7]="Jun08" [8]="Jun09" [9]="Jun10")'

IFS set to space here redundantly to show it works.

Probably the most correct way to go from a string to an array is to use read. Many examples here.

The cannonical method is:

read -ra arr <<<"$str"

where IFS is optionally set in the environment of read to act as a delimiter if it's something other than whitespace.

Solution 2

I suggest not using $IFS on its own to do word-splitting into an array, as setting and reverting $IFS is a pain. Use something like this:

DATES_STRING='Jun01 Jun02 Jun03 Jun04 Jun05'

IFS=' ' read -a DATES_ARRAY <<< "$DATES_STRING"

I also suggest explicitly setting $IFS in read's environment so you're absolutely sure what it is.

Solution 3

The default $IFS is to use whitespace as the token separator, including tabs and newlines.

Try this:

echo "$IFS" | cat -vte

If you haven't changed $IFS, the output should be:

 ^I$
$

That's a space, followed by a single tab: ^I, and a newline - note that cat is printing any newlines as $.

And so your script excerpt should work without touching $IFS.

Share:
39,596
JDS
Author by

JDS

Updated on July 09, 2022

Comments

  • JDS
    JDS almost 2 years

    I'm having trouble using the IFS to convert my string into an array. Here is what I have as my string:

    "Jun01 Jun02 Jun03 Jun04 Jun05 ..." #in that format, separated by spaces
    

    And here is the code I have tried:

    IFS=" " #set it to space character
    DATES_ARRAY=($DATES_STRING) #from above
    echo ${DATES_ARRAY[0]} #output is empty
    

    However when I remove the IFS line it works. But I used a few lines to print out its default ASCII value and I got '32' which means 'Space' character. Being an OCD programmer I'd like to set it myself just to be safe... I don't know how it's going to be preset a priori!

    So why does trying to set IFS to Space manually not work?