63

Possible Duplicate:
Split string based on delimiter in Bash?

In a bash script how do I split string with a separator like ; and loop through the resulting array?

2
  • 1
    This sounds like homework. Regardless, what have you tried so far? Post something that shows you're trying. Commented Sep 10, 2009 at 18:44
  • 1
    not a homework question. just no familiar with shell script. i have been googling but found nothing quite what i am looking for. Commented Sep 10, 2009 at 18:46

5 Answers 5

94

You can probably skip the step of explicitly creating an array...

One trick that I like to use is to set the inter-field separator (IFS) to the delimiter character. This is especially handy for iterating through the space or return delimited results from the stdout of any of a number of unix commands.

Below is an example using semicolons (as you had mentioned in your question):

export IFS=";"
sentence="one;two;three"
for word in $sentence; do
  echo "$word"
done

Note: in regular Bourne-shell scripting setting and exporting the IFS would occur on two separate lines (IFS='x'; export IFS;).

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

5 Comments

I think you should store IFS before modifying it, in an temp variable and restore it back once you are done with it!!
I'd recommend either doing this in a subshell (wrap in parentheses) or saving and restoring IFS (OLDIFS="$IFS" ...code... export IFS="$OLDIFS") - a lot of funky things can happen if it's not set right.
thanks. i am using this script and also saving and restoring ifs according to jefromi. but i get this error export: =: bad variable name did i do something wrong?
It is not necessary to export IFS. Just save it oldIFS=$IFS, set it IFS=';', do stuff, and restore it IFS=$oldIFS.
I would use exprt IFS="," instead because if the input is feed from argument then the argument containing ; could have a different meaning than just a separator
39

If you don't wish to mess with IFS (perhaps for the code within the loop) this might help.

If know that your string will not have whitespace, you can substitute the ';' with a space and use the for/in construct:

#local str
for str in ${STR//;/ } ; do 
   echo "+ \"$str\""
done

But if you might have whitespace, then for this approach you will need to use a temp variable to hold the "rest" like this:

#local str rest
rest=$STR
while [ -n "$rest" ] ; do
   str=${rest%%;*}  # Everything up to the first ';'
   # Trim up to the first ';' -- and handle final case, too.
   [ "$rest" = "${rest/;/}" ] && rest= || rest=${rest#*;}
   echo "+ \"$str\""
done

2 Comments

Why the down-vote w/o a comment? You should justify that....
I use the first method using using ${STR//;/ } syntax. But I got a problem now, that if I pass a string which doesn't have the delimiter, it gives an error: "Bad substitution". I'd like to treat such strings as an array with one element. Do you have any suggestion to get around this issue?
16

Here's a variation on ashirazi's answer which doesn't rely on $IFS. It does have its own issues which I ouline below.

sentence="one;two;three"
sentence=${sentence//;/$'\n'}  # change the semicolons to white space
for word in $sentence
do
    echo "$word"
done

Here I've used a newline, but you could use a tab "\t" or a space. However, if any of those characters are in the text it will be split there, too. That's the advantage of $IFS - it can not only enable a separator, but disable the default ones. Just make sure you save its value before you change it - as others have suggested.

1 Comment

You could just do for word in ${sentence//;/$'\n'} (omit the second assignment). To loop only on newlines, you can do something like echo ${sentence//;/$'\n'} | while read elem; do echo "$elem"; done.
3

Here is an example code that you may use:

$ STR="String;1;2;3"
$ for EACH in `echo "$STR" | grep -o -e "[^;]*"`; do
    echo "Found: \"$EACH\"";
done

grep -o -e "[^;]*" will select anything that is not ';', therefore spliting the string by ';'.

Hope that help.

6 Comments

thanks, but for some reason, it doesnt loop. it only outputs
@Funky Dude: It loops for me.
The '$' in front of STR and for means the shell prompt, You omit that. I am dead sure it work as I using it right now. :D
i did take it out and put it in a shell script
Ummm. That is strange. I really don't know why. Just in case, though, see what I did here: dl.getdropbox.com/u/1961549/images/It_works.jpg .
|
-1
sentence="one;two;three"
a="${sentence};"
while [ -n "${a}" ]
do
    echo ${a%%;*}
    a=${a#*;}
done

1 Comment

An explanation would improve this answer

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.