1

I am trying to initialize read an array by splitting a variable.

x=abc:def:gh
declare -a xa
# I want xa[0] = abc, xa[1] = def, and so on

IFS=: read -a xa <<< $x
echo ${#xa[@]} $xa ######### the above did not work
1 abc def gh

# but type the same value from console?
IFS=: read -a xa
abc:def:gh ########## this is what I typed in
echo ${#xa[@]} $xa ######### this worked
3 abc

How do put IFS to work when reading in a variable using <<< ?

Will appreciate your suggestions.

Also, here is my actual problem, just in case there are smarter solutions to it. I use SVN and different people are interested in knowing about different set of paths. In SVN post-commit, I want to filter the list of changes and raise an email to different groups of people according to their desires. So I thought I would set up something like below in hooks-env

NOTIFY_LIST=mailinglist:grep options:grep options:......

and then, in post-commit, parse the svnlook data to see if there was any candidate email. Is there a declarative way to say that a change in such and such paths are of interest to such and such lists of people?

Thanks Dinesh

edit: tried combination of IFS and simply xa=($x). So it appears IFS=: cannot be combined profitably with read. So I have a way to get my job done, but still curious what's happening?

IFS=: xa=($x) # the array is populated as expected
IFS=b xa=($x) # the array is populated as expected

Thanks again.

1
  • 1
    There were some bugs in earlier versions of bash when using IFS like this with here strings, at least some of which have been fixed in 4.3 See stackoverflow.com/q/20144593/1126841. Commented Aug 14, 2014 at 21:31

2 Answers 2

5

Use more quotes!

IFS=: read -r -a xa <<<"$x"

...works as you expect.

Similarly, if you want to see the contents of an array accurately, echo is the wrong tool, especially when not quoting its arguments. Consider instead:

printf '%q\n' "${xa[@]}"
Sign up to request clarification or add additional context in comments.

4 Comments

There was a bug in pre-4.3 versions of bash, since assuming the default value of IFS, the same string should be seen by read whether or not you quote $x. Without quotes, $x is incorrectly split into three words, but still treated as a single word by read when populating the array.
@chepner, thanks -- I didn't have a good explanation of why quoting here fixed this; that clears it up.
@chepner, thanks for the succinct explanation. Mine is at 4.1.2
It's good that there is a simple workaround; 4.2 doesn't even seem to be widespread in distributions yet, so 4.3 as a default seems to be a ways out (even if distributions do leapfrog directly to 4.3).
1

There is no need to use read. IFS is all you need. (set -f or set -o noglob on as needed to prevent expansion):

#!/bin/bash
## if expansion of '*' or '?' is a concern, then uncomment the next line:
# set -f   # (or set -o noglob on)

x=abc:def:gh
IFS=$':'
arr=( $x )                          # simple assignment will split x


for ((i=0;i<${#arr[@]};i++)); do    # dump the loop values
    echo "arr[$i] ${arr[$i]}"
done

output:

arr[0] abc
arr[1] def
arr[2] gh

or with set -f and x='*':

arr[0] *

2 Comments

This method is subject to pathname expansion or requires disabling pathname expansion. Try x='*'; arr=($x).
Grr.. - you're right of course, but given the problem description I did not see pathname expansion as a criteria. But presuming a need to protect against all possibilities, then you can add set -f or set -o noglob on. (thanks for keeping me on my toes :)

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.