tags:

views:

3690

answers:

5

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

A: 

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.

NawaMan
thanks, but for some reason, it doesnt loop. it only outputs
Funky Dude
Found: "String" once
Funky Dude
@Funky Dude: It loops for me.
Dennis Williamson
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
NawaMan
i did take it out and put it in a shell script
Funky Dude
Ummm. That is strange. I really don't know why. Just in case, though, see what I did here: http://dl.getdropbox.com/u/1961549/images/It_works.jpg .
NawaMan
+4  A: 

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;).

I think you should store IFS before modifying it, in an temp variable and restore it back once you are done with it!!
Aviator
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.
Jefromi
thanks. i am using this script and also saving and restoring ifs according to jefromi. but i get this errorexport: =: bad variable namedid i do something wrong?
Funky Dude
It is not necessary to export IFS. Just save it `oldIFS=$IFS`, set it `IFS=';'`, do stuff, and restore it `IFS=$oldIFS`.
Dennis Williamson
+1  A: 

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.

Dennis Williamson
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`.
Jefromi
A: 

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
NVRAM
Why the down-vote w/o a comment? You should justify that....
NVRAM
A: 

can we do the travers for two variable in the same loop, where the sizes of variables are equal.

Lahiru Gunathilake