9

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?

8
  • 1
    your code worked on bash v3.2.25, what locale are you using? Commented Jul 10, 2012 at 17:25
  • Not sure, how can I find out? Commented Jul 10, 2012 at 17:30
  • 1
    Works on GNU bash, version 4.2.29 for me. Try putting the space like ' ' and see if it makes any difference. Commented Jul 10, 2012 at 17:37
  • Just answered something similar a few minutes ago: stackoverflow.com/a/11416230/1327576 Commented Jul 10, 2012 at 17:38
  • 1
    @YoungMoney, in what way does it differ from expected behaviour? It works for me: string="a b c d e"; tokens=(${string}); echo "Third token: ${tokens[2]}" prints Third token: c as I would expect. Commented Jul 10, 2012 at 18:25

3 Answers 3

13

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.

Sign up to request clarification or add additional context in comments.

Comments

7

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.

1 Comment

doesn't that change IFS any way?
1

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.

3 Comments

Alright but I don't understand why trying to set it to a Space myself doesn't work. Good to know what the default is though.
cat -te is equivalent to cat -vTE so you can skip the -v.
Also declare -p IFS will display it unambiguously.

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.