How do I split a string on a delimiter in Bash?











up vote
1605
down vote

favorite
465












I have this string stored in a variable:



IN="bla@some.com;john@home.com"


Now I would like to split the strings by ; delimiter so that I have:



ADDR1="bla@some.com"
ADDR2="john@home.com"


I don't necessarily need the ADDR1 and ADDR2 variables. If they are elements of an array that's even better.





After suggestions from the answers below, I ended up with the following which is what I was after:



#!/usr/bin/env bash

IN="bla@some.com;john@home.com"

mails=$(echo $IN | tr ";" "n")

for addr in $mails
do
echo "> [$addr]"
done


Output:



> [bla@some.com]
> [john@home.com]


There was a solution involving setting Internal_field_separator (IFS) to ;. I am not sure what happened with that answer, how do you reset IFS back to default?



RE: IFS solution, I tried this and it works, I keep the old IFS and then restore it:



IN="bla@some.com;john@home.com"

OIFS=$IFS
IFS=';'
mails2=$IN
for x in $mails2
do
echo "> [$x]"
done

IFS=$OIFS


BTW, when I tried



mails2=($IN)


I only got the first string when printing it in loop, without brackets around $IN it works.










share|improve this question




















  • 13




    With regards to your "Edit2": You can simply "unset IFS" and it will return to the default state. There's no need to save and restore it explicitly unless you have some reason to expect that it's already been set to a non-default value. Moreover, if you're doing this inside a function (and, if you aren't, why not?), you can set IFS as a local variable and it will return to its previous value once you exit the function.
    – Brooks Moses
    May 1 '12 at 1:26








  • 17




    @BrooksMoses: (a) +1 for using local IFS=... where possible; (b) -1 for unset IFS, this doesn't exactly reset IFS to its default value, though I believe an unset IFS behaves the same as the default value of IFS ($' tn'), however it seems bad practice to be assuming blindly that your code will never be invoked with IFS set to a custom value; (c) another idea is to invoke a subshell: (IFS=$custom; ...) when the subshell exits IFS will return to whatever it was originally.
    – dubiousjim
    May 31 '12 at 5:21










  • I just want to have a quick look at the paths to decide where to throw an executable, so I resorted to run ruby -e "puts ENV.fetch('PATH').split(':')". If you want to stay pure bash won't help but using any scripting language that has a built-in split is easier.
    – nicooga
    Mar 7 '16 at 15:32










  • This is kind of a drive-by comment, but since the OP used email addresses as the example, has anyone bothered to answer it in a way that is fully RFC 5322 compliant, namely that any quoted string can appear before the @ which means you're going to need regular expressions or some other kind of parser instead of naive use of IFS or other simplistic splitter functions.
    – Jeff
    Apr 22 at 17:51






  • 1




    for x in $(IFS=';';echo $IN); do echo "> [$x]"; done
    – user2037659
    Apr 26 at 20:15

















up vote
1605
down vote

favorite
465












I have this string stored in a variable:



IN="bla@some.com;john@home.com"


Now I would like to split the strings by ; delimiter so that I have:



ADDR1="bla@some.com"
ADDR2="john@home.com"


I don't necessarily need the ADDR1 and ADDR2 variables. If they are elements of an array that's even better.





After suggestions from the answers below, I ended up with the following which is what I was after:



#!/usr/bin/env bash

IN="bla@some.com;john@home.com"

mails=$(echo $IN | tr ";" "n")

for addr in $mails
do
echo "> [$addr]"
done


Output:



> [bla@some.com]
> [john@home.com]


There was a solution involving setting Internal_field_separator (IFS) to ;. I am not sure what happened with that answer, how do you reset IFS back to default?



RE: IFS solution, I tried this and it works, I keep the old IFS and then restore it:



IN="bla@some.com;john@home.com"

OIFS=$IFS
IFS=';'
mails2=$IN
for x in $mails2
do
echo "> [$x]"
done

IFS=$OIFS


BTW, when I tried



mails2=($IN)


I only got the first string when printing it in loop, without brackets around $IN it works.










share|improve this question




















  • 13




    With regards to your "Edit2": You can simply "unset IFS" and it will return to the default state. There's no need to save and restore it explicitly unless you have some reason to expect that it's already been set to a non-default value. Moreover, if you're doing this inside a function (and, if you aren't, why not?), you can set IFS as a local variable and it will return to its previous value once you exit the function.
    – Brooks Moses
    May 1 '12 at 1:26








  • 17




    @BrooksMoses: (a) +1 for using local IFS=... where possible; (b) -1 for unset IFS, this doesn't exactly reset IFS to its default value, though I believe an unset IFS behaves the same as the default value of IFS ($' tn'), however it seems bad practice to be assuming blindly that your code will never be invoked with IFS set to a custom value; (c) another idea is to invoke a subshell: (IFS=$custom; ...) when the subshell exits IFS will return to whatever it was originally.
    – dubiousjim
    May 31 '12 at 5:21










  • I just want to have a quick look at the paths to decide where to throw an executable, so I resorted to run ruby -e "puts ENV.fetch('PATH').split(':')". If you want to stay pure bash won't help but using any scripting language that has a built-in split is easier.
    – nicooga
    Mar 7 '16 at 15:32










  • This is kind of a drive-by comment, but since the OP used email addresses as the example, has anyone bothered to answer it in a way that is fully RFC 5322 compliant, namely that any quoted string can appear before the @ which means you're going to need regular expressions or some other kind of parser instead of naive use of IFS or other simplistic splitter functions.
    – Jeff
    Apr 22 at 17:51






  • 1




    for x in $(IFS=';';echo $IN); do echo "> [$x]"; done
    – user2037659
    Apr 26 at 20:15















up vote
1605
down vote

favorite
465









up vote
1605
down vote

favorite
465






465





I have this string stored in a variable:



IN="bla@some.com;john@home.com"


Now I would like to split the strings by ; delimiter so that I have:



ADDR1="bla@some.com"
ADDR2="john@home.com"


I don't necessarily need the ADDR1 and ADDR2 variables. If they are elements of an array that's even better.





After suggestions from the answers below, I ended up with the following which is what I was after:



#!/usr/bin/env bash

IN="bla@some.com;john@home.com"

mails=$(echo $IN | tr ";" "n")

for addr in $mails
do
echo "> [$addr]"
done


Output:



> [bla@some.com]
> [john@home.com]


There was a solution involving setting Internal_field_separator (IFS) to ;. I am not sure what happened with that answer, how do you reset IFS back to default?



RE: IFS solution, I tried this and it works, I keep the old IFS and then restore it:



IN="bla@some.com;john@home.com"

OIFS=$IFS
IFS=';'
mails2=$IN
for x in $mails2
do
echo "> [$x]"
done

IFS=$OIFS


BTW, when I tried



mails2=($IN)


I only got the first string when printing it in loop, without brackets around $IN it works.










share|improve this question















I have this string stored in a variable:



IN="bla@some.com;john@home.com"


Now I would like to split the strings by ; delimiter so that I have:



ADDR1="bla@some.com"
ADDR2="john@home.com"


I don't necessarily need the ADDR1 and ADDR2 variables. If they are elements of an array that's even better.





After suggestions from the answers below, I ended up with the following which is what I was after:



#!/usr/bin/env bash

IN="bla@some.com;john@home.com"

mails=$(echo $IN | tr ";" "n")

for addr in $mails
do
echo "> [$addr]"
done


Output:



> [bla@some.com]
> [john@home.com]


There was a solution involving setting Internal_field_separator (IFS) to ;. I am not sure what happened with that answer, how do you reset IFS back to default?



RE: IFS solution, I tried this and it works, I keep the old IFS and then restore it:



IN="bla@some.com;john@home.com"

OIFS=$IFS
IFS=';'
mails2=$IN
for x in $mails2
do
echo "> [$x]"
done

IFS=$OIFS


BTW, when I tried



mails2=($IN)


I only got the first string when printing it in loop, without brackets around $IN it works.







bash shell split scripting






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Oct 22 at 21:20









codeforester

17.1k83863




17.1k83863










asked May 28 '09 at 2:03









stefanB

47.2k24105134




47.2k24105134








  • 13




    With regards to your "Edit2": You can simply "unset IFS" and it will return to the default state. There's no need to save and restore it explicitly unless you have some reason to expect that it's already been set to a non-default value. Moreover, if you're doing this inside a function (and, if you aren't, why not?), you can set IFS as a local variable and it will return to its previous value once you exit the function.
    – Brooks Moses
    May 1 '12 at 1:26








  • 17




    @BrooksMoses: (a) +1 for using local IFS=... where possible; (b) -1 for unset IFS, this doesn't exactly reset IFS to its default value, though I believe an unset IFS behaves the same as the default value of IFS ($' tn'), however it seems bad practice to be assuming blindly that your code will never be invoked with IFS set to a custom value; (c) another idea is to invoke a subshell: (IFS=$custom; ...) when the subshell exits IFS will return to whatever it was originally.
    – dubiousjim
    May 31 '12 at 5:21










  • I just want to have a quick look at the paths to decide where to throw an executable, so I resorted to run ruby -e "puts ENV.fetch('PATH').split(':')". If you want to stay pure bash won't help but using any scripting language that has a built-in split is easier.
    – nicooga
    Mar 7 '16 at 15:32










  • This is kind of a drive-by comment, but since the OP used email addresses as the example, has anyone bothered to answer it in a way that is fully RFC 5322 compliant, namely that any quoted string can appear before the @ which means you're going to need regular expressions or some other kind of parser instead of naive use of IFS or other simplistic splitter functions.
    – Jeff
    Apr 22 at 17:51






  • 1




    for x in $(IFS=';';echo $IN); do echo "> [$x]"; done
    – user2037659
    Apr 26 at 20:15
















  • 13




    With regards to your "Edit2": You can simply "unset IFS" and it will return to the default state. There's no need to save and restore it explicitly unless you have some reason to expect that it's already been set to a non-default value. Moreover, if you're doing this inside a function (and, if you aren't, why not?), you can set IFS as a local variable and it will return to its previous value once you exit the function.
    – Brooks Moses
    May 1 '12 at 1:26








  • 17




    @BrooksMoses: (a) +1 for using local IFS=... where possible; (b) -1 for unset IFS, this doesn't exactly reset IFS to its default value, though I believe an unset IFS behaves the same as the default value of IFS ($' tn'), however it seems bad practice to be assuming blindly that your code will never be invoked with IFS set to a custom value; (c) another idea is to invoke a subshell: (IFS=$custom; ...) when the subshell exits IFS will return to whatever it was originally.
    – dubiousjim
    May 31 '12 at 5:21










  • I just want to have a quick look at the paths to decide where to throw an executable, so I resorted to run ruby -e "puts ENV.fetch('PATH').split(':')". If you want to stay pure bash won't help but using any scripting language that has a built-in split is easier.
    – nicooga
    Mar 7 '16 at 15:32










  • This is kind of a drive-by comment, but since the OP used email addresses as the example, has anyone bothered to answer it in a way that is fully RFC 5322 compliant, namely that any quoted string can appear before the @ which means you're going to need regular expressions or some other kind of parser instead of naive use of IFS or other simplistic splitter functions.
    – Jeff
    Apr 22 at 17:51






  • 1




    for x in $(IFS=';';echo $IN); do echo "> [$x]"; done
    – user2037659
    Apr 26 at 20:15










13




13




With regards to your "Edit2": You can simply "unset IFS" and it will return to the default state. There's no need to save and restore it explicitly unless you have some reason to expect that it's already been set to a non-default value. Moreover, if you're doing this inside a function (and, if you aren't, why not?), you can set IFS as a local variable and it will return to its previous value once you exit the function.
– Brooks Moses
May 1 '12 at 1:26






With regards to your "Edit2": You can simply "unset IFS" and it will return to the default state. There's no need to save and restore it explicitly unless you have some reason to expect that it's already been set to a non-default value. Moreover, if you're doing this inside a function (and, if you aren't, why not?), you can set IFS as a local variable and it will return to its previous value once you exit the function.
– Brooks Moses
May 1 '12 at 1:26






17




17




@BrooksMoses: (a) +1 for using local IFS=... where possible; (b) -1 for unset IFS, this doesn't exactly reset IFS to its default value, though I believe an unset IFS behaves the same as the default value of IFS ($' tn'), however it seems bad practice to be assuming blindly that your code will never be invoked with IFS set to a custom value; (c) another idea is to invoke a subshell: (IFS=$custom; ...) when the subshell exits IFS will return to whatever it was originally.
– dubiousjim
May 31 '12 at 5:21




@BrooksMoses: (a) +1 for using local IFS=... where possible; (b) -1 for unset IFS, this doesn't exactly reset IFS to its default value, though I believe an unset IFS behaves the same as the default value of IFS ($' tn'), however it seems bad practice to be assuming blindly that your code will never be invoked with IFS set to a custom value; (c) another idea is to invoke a subshell: (IFS=$custom; ...) when the subshell exits IFS will return to whatever it was originally.
– dubiousjim
May 31 '12 at 5:21












I just want to have a quick look at the paths to decide where to throw an executable, so I resorted to run ruby -e "puts ENV.fetch('PATH').split(':')". If you want to stay pure bash won't help but using any scripting language that has a built-in split is easier.
– nicooga
Mar 7 '16 at 15:32




I just want to have a quick look at the paths to decide where to throw an executable, so I resorted to run ruby -e "puts ENV.fetch('PATH').split(':')". If you want to stay pure bash won't help but using any scripting language that has a built-in split is easier.
– nicooga
Mar 7 '16 at 15:32












This is kind of a drive-by comment, but since the OP used email addresses as the example, has anyone bothered to answer it in a way that is fully RFC 5322 compliant, namely that any quoted string can appear before the @ which means you're going to need regular expressions or some other kind of parser instead of naive use of IFS or other simplistic splitter functions.
– Jeff
Apr 22 at 17:51




This is kind of a drive-by comment, but since the OP used email addresses as the example, has anyone bothered to answer it in a way that is fully RFC 5322 compliant, namely that any quoted string can appear before the @ which means you're going to need regular expressions or some other kind of parser instead of naive use of IFS or other simplistic splitter functions.
– Jeff
Apr 22 at 17:51




1




1




for x in $(IFS=';';echo $IN); do echo "> [$x]"; done
– user2037659
Apr 26 at 20:15






for x in $(IFS=';';echo $IN); do echo "> [$x]"; done
– user2037659
Apr 26 at 20:15














33 Answers
33






active

oldest

votes













1 2
next











up vote
978
down vote



accepted










You can set the internal field separator (IFS) variable, and then let it parse into an array. When this happens in a command, then the assignment to IFS only takes place to that single command's environment (to read ). It then parses the input according to the IFS variable value into an array, which we can then iterate over.



IFS=';' read -ra ADDR <<< "$IN"
for i in "${ADDR[@]}"; do
# process "$i"
done


It will parse one line of items separated by ;, pushing it into an array. Stuff for processing whole of $IN, each time one line of input separated by ;:



 while IFS=';' read -ra ADDR; do
for i in "${ADDR[@]}"; do
# process "$i"
done
done <<< "$IN"





share|improve this answer



















  • 16




    This is probably the best way. How long will IFS persist in it's current value, can it mess up my code by being set when it shouldn't be, and how can I reset it when I'm done with it?
    – Chris Lutz
    May 28 '09 at 2:25






  • 6




    now after the fix applied, only within the duration of the read command :)
    – Johannes Schaub - litb
    May 28 '09 at 3:04






  • 14




    You can read everything at once without using a while loop: read -r -d '' -a addr <<< "$in" # The -d '' is key here, it tells read not to stop at the first newline (which is the default -d) but to continue until EOF or a NULL byte (which only occur in binary data).
    – lhunath
    May 28 '09 at 6:14






  • 39




    @LucaBorrione Setting IFS on the same line as the read with no semicolon or other separator, as opposed to in a separate command, scopes it to that command -- so it's always "restored"; you don't need to do anything manually.
    – Charles Duffy
    Jul 6 '13 at 14:39








  • 5




    @imagineerThis There is a bug involving herestrings and local changes to IFS that requires $IN to be quoted. The bug is fixed in bash 4.3.
    – chepner
    Oct 2 '14 at 3:50


















up vote
787
down vote













Taken from Bash shell script split array:



IN="bla@some.com;john@home.com"
arrIN=(${IN//;/ })


Explanation:



This construction replaces all occurrences of ';' (the initial // means global replace) in the string IN with ' ' (a single space), then interprets the space-delimited string as an array (that's what the surrounding parentheses do).



The syntax used inside of the curly braces to replace each ';' character with a ' ' character is called Parameter Expansion.



There are some common gotchas:




  1. If the original string has spaces, you will need to use IFS:


    • IFS=':'; arrIN=($IN); unset IFS;



  2. If the original string has spaces and the delimiter is a new line, you can set IFS with:


    • IFS=$'n'; arrIN=($IN); unset IFS;








share|improve this answer



















  • 70




    I just want to add: this is the simplest of all, you can access array elements with ${arrIN[1]} (starting from zeros of course)
    – Oz123
    Mar 21 '11 at 18:50






  • 23




    Found it: the technique of modifying a variable within a ${} is known as 'parameter expansion'.
    – KomodoDave
    Jan 5 '12 at 15:13






  • 23




    Does it work when the original string contains spaces?
    – qbolec
    Feb 25 '13 at 9:12






  • 21




    No, I don't think this works when there are also spaces present... it's converting the ',' to ' ' and then building a space-separated array.
    – Ethan
    Apr 12 '13 at 22:47






  • 41




    This is a bad approach for other reasons: For instance, if your string contains ;*;, then the * will be expanded to a list of filenames in the current directory. -1
    – Charles Duffy
    Jul 6 '13 at 14:39


















up vote
215
down vote













If you don't mind processing them immediately, I like to do this:



for i in $(echo $IN | tr ";" "n")
do
# process
done


You could use this kind of loop to initialize an array, but there's probably an easier way to do it. Hope this helps, though.






share|improve this answer





















  • You should have kept the IFS answer. It taught me something I didn't know, and it definitely made an array, whereas this just makes a cheap substitute.
    – Chris Lutz
    May 28 '09 at 2:42










  • I see. Yeah i find doing these silly experiments, i'm going to learn new things each time i'm trying to answer things. I've edited stuff based on #bash IRC feedback and undeleted :)
    – Johannes Schaub - litb
    May 28 '09 at 2:59






  • 31




    -1, you're obviously not aware of wordsplitting, because it's introducing two bugs in your code. one is when you don't quote $IN and the other is when you pretend a newline is the only delimiter used in wordsplitting. You are iterating over every WORD in IN, not every line, and DEFINATELY not every element delimited by a semicolon, though it may appear to have the side-effect of looking like it works.
    – lhunath
    May 28 '09 at 6:12






  • 2




    You could change it to echo "$IN" | tr ';' 'n' | while read -r ADDY; do # process "$ADDY"; done to make him lucky, i think :) Note that this will fork, and you can't change outer variables from within the loop (that's why i used the <<< "$IN" syntax) then
    – Johannes Schaub - litb
    May 28 '09 at 17:00






  • 7




    To summarize the debate in the comments: Caveats for general use: the shell applies word splitting and expansions to the string, which may be undesired; just try it with. IN="bla@some.com;john@home.com;*;broken apart". In short: this approach will break, if your tokens contain embedded spaces and/or chars. such as * that happen to make a token match filenames in the current folder.
    – mklement0
    Apr 24 '13 at 14:13


















up vote
139
down vote













Compatible answer



To this SO question, there is already a lot of different way to do this in bash.
But bash has many special features, so called bashism that work well, but that won't work in any other shell.



In particular, arrays, associative array, and pattern substitution are pure bashisms and may not work under other shells.



On my Debian GNU/Linux, there is a standard shell called dash, but I know many people who like to use ksh.



Finally, in very small situation, there is a special tool called busybox with his own shell interpreter (ash).



Requested string



The string sample in SO question is:



IN="bla@some.com;john@home.com"


As this could be useful with whitespaces and as whitespaces could modify the result of the routine, I prefer to use this sample string:



 IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"


Split string based on delimiter in bash (version >=4.2)



Under pure bash, we may use arrays and IFS:



var="bla@some.com;john@home.com;Full Name <fulnam@other.org>"




oIFS="$IFS"
IFS=";"
declare -a fields=($var)
IFS="$oIFS"
unset oIFS




IFS=; read -a fields <<<"$IN"


Using this syntax under recent bash don't change $IFS for current session, but only for the current command:



set | grep ^IFS=
IFS=$' tn'


Now the string var is split and stored into an array (named fields):



set | grep ^fields=\|^var=
fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")
var='bla@some.com;john@home.com;Full Name <fulnam@other.org>'


We could request for variable content with declare -p:



declare -p IN fields
declare -- IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
declare -a fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")


read is the quickiest way to do the split, because there is no forks and no external resources called.



From there, you could use the syntax you already know for processing each field:



for x in "${fields[@]}";do
echo "> [$x]"
done
> [bla@some.com]
> [john@home.com]
> [Full Name <fulnam@other.org>]


or drop each field after processing (I like this shifting approach):



while [ "$fields" ] ;do
echo "> [$fields]"
fields=("${fields[@]:1}")
done
> [bla@some.com]
> [john@home.com]
> [Full Name <fulnam@other.org>]


or even for simple printout (shorter syntax):



printf "> [%s]n" "${fields[@]}"
> [bla@some.com]
> [john@home.com]
> [Full Name <fulnam@other.org>]


Update: recent bash >= 4.4



You could play with mapfile:



mapfile -td ; fields < <(printf "%s" "$IN")


This syntax preserve special chars, newlines and empty fields!



If you don't care about empty fields, you could:



mapfile -td ; fields <<<"$IN"
fields=("${fields[@]%$'n'}") # drop 'n' added by '<<<'


But you could use fields through function:



myPubliMail() {
printf "Seq: %6d: Sending mail to '%s'..." $1 "$2"
# mail -s "This is not a spam..." "$2" </path/to/body
printf "e[3D, done.n"
}

mapfile < <(printf "%s" "$IN") -td ; -c 1 -C myPubliMail


(Nota: at end of format string are useless while you don't care about empty fields at end of string)



mapfile < <(echo -n "$IN") -td ; -c 1 -C myPubliMail


Will render something like:



Seq:      0: Sending mail to 'bla@some.com', done.
Seq: 1: Sending mail to 'john@home.com', done.
Seq: 2: Sending mail to 'Full Name <fulnam@other.org>', done.


Or Drop newline added by <<< bash syntax in function:



myPubliMail() {
local seq=$1 dest="${2%$'n'}"
printf "Seq: %6d: Sending mail to '%s'..." $seq "$dest"
# mail -s "This is not a spam..." "$dest" </path/to/body
printf "e[3D, done.n"
}

mapfile <<<"$IN" -td ; -c 1 -C myPubliMail


Will render same output:



Seq:      0: Sending mail to 'bla@some.com', done.
Seq: 1: Sending mail to 'john@home.com', done.
Seq: 2: Sending mail to 'Full Name <fulnam@other.org>', done.


Split string based on delimiter in shell



But if you would write something usable under many shells, you have to not use bashisms.



There is a syntax, used in many shells, for splitting a string across first or last occurrence of a substring:



${var#*SubStr}  # will drop begin of string up to first occur of `SubStr`
${var##*SubStr} # will drop begin of string up to last occur of `SubStr`
${var%SubStr*} # will drop part of string from last occur of `SubStr` to the end
${var%%SubStr*} # will drop part of string from first occur of `SubStr` to the end


(The missing of this is the main reason of my answer publication ;)



As pointed out by Score_Under:




# and % delete the shortest possible matching string, and



## and %% delete the longest possible.



where # and ## mean from left (begin) of string, and



% and %% meand from right (end) of string.




This little sample script work well under bash, dash, ksh, busybox and was tested under Mac-OS's bash too:



var="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
while [ "$var" ] ;do
iter=${var%%;*}
echo "> [$iter]"
[ "$var" = "$iter" ] &&
var='' ||
var="${var#*;}"
done
> [bla@some.com]
> [john@home.com]
> [Full Name <fulnam@other.org>]


Have fun!






share|improve this answer



















  • 11




    The #, ##, %, and %% substitutions have what is IMO an easier explanation to remember (for how much they delete): # and % delete the shortest possible matching string, and ## and %% delete the longest possible.
    – Score_Under
    Apr 28 '15 at 16:58








  • 1




    The IFS=; read -a fields <<<"$var" fails on newlines and add a trailing newline. The other solution removes a trailing empty field.
    – sorontar
    Oct 26 '16 at 4:36










  • The shell delimiter is the most elegant answer, period.
    – Eric Chen
    Aug 30 '17 at 17:50












  • Could the last alternative be used with a list of field separators set somewhere else? For instance, I mean to use this as a shell script, and pass a list of field separators as a positional parameter.
    – sancho.s
    Oct 4 at 3:42










  • Yes, in a loop: for sep in "#" "ł" "@" ; do ... var="${var#*$sep}" ...
    – F. Hauri
    Oct 4 at 7:47




















up vote
96
down vote













I've seen a couple of answers referencing the cut command, but they've all been deleted. It's a little odd that nobody has elaborated on that, because I think it's one of the more useful commands for doing this type of thing, especially for parsing delimited log files.



In the case of splitting this specific example into a bash script array, tr is probably more efficient, but cut can be used, and is more effective if you want to pull specific fields from the middle.



Example:



$ echo "bla@some.com;john@home.com" | cut -d ";" -f 1
bla@some.com
$ echo "bla@some.com;john@home.com" | cut -d ";" -f 2
john@home.com


You can obviously put that into a loop, and iterate the -f parameter to pull each field independently.



This gets more useful when you have a delimited log file with rows like this:



2015-04-27|12345|some action|an attribute|meta data


cut is very handy to be able to cat this file and select a particular field for further processing.






share|improve this answer



















  • 2




    Kudos for using cut, it's the right tool for the job! Much cleared than any of those shell hacks.
    – MisterMiyagi
    Nov 2 '16 at 8:42






  • 2




    This approach will only work if you know the number of elements in advance; you'd need to program some more logic around it. It also runs an external tool for every element.
    – uli42
    Sep 14 '17 at 8:30










  • Excatly waht i was looking for trying to avoid empty string in a csv. Now i can point the exact 'column' value as well. Work with IFS already used in a loop. Better than expected for my situation.
    – Louis Loudog Trottier
    May 10 at 4:20


















up vote
81
down vote













How about this approach:



IN="bla@some.com;john@home.com" 
set -- "$IN"
IFS=";"; declare -a Array=($*)
echo "${Array[@]}"
echo "${Array[0]}"
echo "${Array[1]}"


Source






share|improve this answer



















  • 6




    +1 ... but I wouldn't name the variable "Array" ... pet peev I guess. Good solution.
    – Yzmir Ramirez
    Sep 5 '11 at 1:06






  • 14




    +1 ... but the "set" and declare -a are unnecessary. You could as well have used just IFS";" && Array=($IN)
    – ata
    Nov 3 '11 at 22:33












  • +1 Only a side note: shouldn't it be recommendable to keep the old IFS and then restore it? (as shown by stefanB in his edit3) people landing here (sometimes just copying and pasting a solution) might not think about this
    – Luca Borrione
    Sep 3 '12 at 9:26






  • 6




    -1: First, @ata is right that most of the commands in this do nothing. Second, it uses word-splitting to form the array, and doesn't do anything to inhibit glob-expansion when doing so (so if you have glob characters in any of the array elements, those elements are replaced with matching filenames).
    – Charles Duffy
    Jul 6 '13 at 14:44






  • 1




    Suggest to use $'...': IN=$'bla@some.com;john@home.com;bet <d@ns* kl.com>'. Then echo "${Array[2]}" will print a string with newline. set -- "$IN" is also neccessary in this case. Yes, to prevent glob expansion, the solution should include set -f.
    – John_West
    Jan 8 '16 at 12:29


















up vote
79
down vote













This worked for me:



string="1;2"
echo $string | cut -d';' -f1 # output is 1
echo $string | cut -d';' -f2 # output is 2





share|improve this answer























  • this is sort and sweet :)
    – Pardeep Sharma
    Oct 10 '17 at 7:29










  • Thanks...Helped a lot
    – space earth
    Oct 17 '17 at 7:23










  • cut works only with a single char as delimiter.
    – mojjj
    Jan 8 at 8:57


















up vote
59
down vote













echo "bla@some.com;john@home.com" | sed -e 's/;/n/g'
bla@some.com
john@home.com





share|improve this answer

















  • 3




    -1 what if the string contains spaces? for example IN="this is first line; this is second line" arrIN=( $( echo "$IN" | sed -e 's/;/n/g' ) ) will produce an array of 8 elements in this case (an element for each word space separated), rather than 2 (an element for each line semi colon separated)
    – Luca Borrione
    Sep 3 '12 at 10:08






  • 2




    @Luca No the sed script creates exactly two lines. What creates the multiple entries for you is when you put it into a bash array (which splits on white space by default)
    – lothar
    Sep 3 '12 at 17:33










  • That's exactly the point: the OP needs to store entries into an array to loop over it, as you can see in his edits. I think your (good) answer missed to mention to use arrIN=( $( echo "$IN" | sed -e 's/;/n/g' ) ) to achieve that, and to advice to change IFS to IFS=$'n' for those who land here in the future and needs to split a string containing spaces. (and to restore it back afterwards). :)
    – Luca Borrione
    Sep 4 '12 at 7:09






  • 1




    @Luca Good point. However the array assignment was not in the initial question when I wrote up that answer.
    – lothar
    Sep 4 '12 at 16:55


















up vote
59
down vote













This also works:



IN="bla@some.com;john@home.com"
echo ADD1=`echo $IN | cut -d ; -f 1`
echo ADD2=`echo $IN | cut -d ; -f 2`


Be careful, this solution is not always correct. In case you pass "bla@some.com" only, it will assign it to both ADD1 and ADD2.






share|improve this answer



















  • 1




    You can use -s to avoid the mentioned problem: superuser.com/questions/896800/… "-f, --fields=LIST select only these fields; also print any line that contains no delimiter character, unless the -s option is specified"
    – fersarr
    Mar 3 '16 at 17:17


















up vote
34
down vote













I think AWK is the best and efficient command to resolve your problem. AWK is included in Bash by default in almost every Linux distribution.



echo "bla@some.com;john@home.com" | awk -F';' '{print $1,$2}'


will give



bla@some.com john@home.com


Of course your can store each email address by redefining the awk print field.






share|improve this answer



















  • 2




    Or even simpler: echo "bla@some.com;john@home.com" | awk 'BEGIN{RS=";"} {print}'
    – Jaro
    Jan 7 '14 at 21:30












  • @Jaro This worked perfectly for me when I had a string with commas and needed to reformat it into lines. Thanks.
    – Aquarelle
    May 6 '14 at 21:58










  • It worked in this scenario -> "echo "$SPLIT_0" | awk -F' inode=' '{print $1}'"! I had problems when trying to use atrings (" inode=") instead of characters (";"). $ 1, $ 2, $ 3, $ 4 are set as positions in an array! If there is a way of setting an array... better! Thanks!
    – Eduardo Lucio
    Aug 5 '15 at 12:59










  • @EduardoLucio, what I'm thinking about is maybe you can first replace your delimiter inode= into ; for example by sed -i 's/inode=/;/g' your_file_to_process, then define -F';' when apply awk, hope that can help you.
    – Tony
    Aug 6 '15 at 2:42




















up vote
26
down vote













A different take on Darron's answer, this is how I do it:



IN="bla@some.com;john@home.com"
read ADDR1 ADDR2 <<<$(IFS=";"; echo $IN)





share|improve this answer























  • This doesn't work.
    – ColinM
    Sep 10 '11 at 0:31










  • I think it does! Run the commands above and then "echo $ADDR1 ... $ADDR2" and i get "bla@some.com ... john@home.com" output
    – nickjb
    Oct 6 '11 at 15:33








  • 1




    This worked REALLY well for me... I used it to itterate over an array of strings which contained comma separated DB,SERVER,PORT data to use mysqldump.
    – Nick
    Oct 28 '11 at 14:36






  • 5




    Diagnosis: the IFS=";" assignment exists only in the $(...; echo $IN) subshell; this is why some readers (including me) initially think it won't work. I assumed that all of $IN was getting slurped up by ADDR1. But nickjb is correct; it does work. The reason is that echo $IN command parses its arguments using the current value of $IFS, but then echoes them to stdout using a space delimiter, regardless of the setting of $IFS. So the net effect is as though one had called read ADDR1 ADDR2 <<< "bla@some.com john@home.com" (note the input is space-separated not ;-separated).
    – dubiousjim
    May 31 '12 at 5:28








  • 1




    This fails on spaces and newlines, and also expand wildcards * in the echo $IN with an unquoted variable expansion.
    – sorontar
    Oct 26 '16 at 4:43


















up vote
24
down vote













In Bash, a bullet proof way, that will work even if your variable contains newlines:



IFS=';' read -d '' -ra array < <(printf '%s;' "$in")


Look:



$ in=$'one;two three;*;there isna newlinenin this field'
$ IFS=';' read -d '' -ra array < <(printf '%s;' "$in")
$ declare -p array
declare -a array='([0]="one" [1]="two three" [2]="*" [3]="there is
a newline
in this field")'


The trick for this to work is to use the -d option of read (delimiter) with an empty delimiter, so that read is forced to read everything it's fed. And we feed read with exactly the content of the variable in, with no trailing newline thanks to printf. Note that's we're also putting the delimiter in printf to ensure that the string passed to read has a trailing delimiter. Without it, read would trim potential trailing empty fields:



$ in='one;two;three;'    # there's an empty field
$ IFS=';' read -d '' -ra array < <(printf '%s;' "$in")
$ declare -p array
declare -a array='([0]="one" [1]="two" [2]="three" [3]="")'


the trailing empty field is preserved.





Update for Bash≥4.4



Since Bash 4.4, the builtin mapfile (aka readarray) supports the -d option to specify a delimiter. Hence another canonical way is:



mapfile -d ';' -t array < <(printf '%s;' "$in")





share|improve this answer



















  • 4




    I found it as the rare solution on that list that works correctly with n, spaces and * simultaneously. Also, no loops; array variable is accessible in the shell after execution (contrary to the highest upvoted answer). Note, in=$'...', it does not work with double quotes. I think, it needs more upvotes.
    – John_West
    Jan 8 '16 at 12:10




















up vote
18
down vote













How about this one liner, if you're not using arrays:



IFS=';' read ADDR1 ADDR2 <<<$IN





share|improve this answer





















  • Consider using read -r ... to ensure that, for example, the two characters "t" in the input end up as the same two characters in your variables (instead of a single tab char).
    – dubiousjim
    May 31 '12 at 5:36










  • -1 This is not working here (ubuntu 12.04). Adding echo "ADDR1 $ADDR1"n echo "ADDR2 $ADDR2" to your snippet will output ADDR1 bla@some.com john@home.comnADDR2 (n is newline)
    – Luca Borrione
    Sep 3 '12 at 10:07










  • This is probably due to a bug involving IFS and here strings that was fixed in bash 4.3. Quoting $IN should fix it. (In theory, $IN is not subject to word splitting or globbing after it expands, meaning the quotes should be unnecessary. Even in 4.3, though, there's at least one bug remaining--reported and scheduled to be fixed--so quoting remains a good idea.)
    – chepner
    Sep 19 '15 at 13:59










  • This breaks if $in contain newlines even if $IN is quoted. And adds a trailing newline.
    – sorontar
    Oct 26 '16 at 4:55


















up vote
17
down vote













Here is a clean 3-liner:



in="foo@bar;bizz@buzz;fizz@buzz;buzz@woof"
IFS=';' list=($in)
for item in "${list[@]}"; do echo $item; done


where IFS delimit words based on the separator and () is used to create an array. Then [@] is used to return each item as a separate word.



If you've any code after that, you also need to restore $IFS, e.g. unset IFS.






share|improve this answer



















  • 4




    The use of $in unquoted allows wildcards to be expanded.
    – sorontar
    Oct 26 '16 at 5:03






  • 1




    + for the unset command
    – user2720864
    Sep 24 at 13:46


















up vote
16
down vote













Without setting the IFS



If you just have one colon you can do that:



a="foo:bar"
b=${a%:*}
c=${a##*:}


you will get:



b = foo
c = bar





share|improve this answer




























    up vote
    7
    down vote













    There is a simple and smart way like this:



    echo "add:sfff" | xargs -d: -i  echo {}


    But you must use gnu xargs, BSD xargs cant support -d delim. If you use apple mac like me. You can install gnu xargs :



    brew install findutils


    then



    echo "add:sfff" | gxargs -d: -i  echo {}





    share|improve this answer




























      up vote
      5
      down vote













      The following Bash/zsh function splits its first argument on the delimiter given by the second argument:



      split() {
      local string="$1"
      local delimiter="$2"
      if [ -n "$string" ]; then
      local part
      while read -d "$delimiter" part; do
      echo $part
      done <<< "$string"
      echo $part
      fi
      }


      For instance, the command



      $ split 'a;b;c' ';'


      yields



      a
      b
      c


      This output may, for instance, be piped to other commands. Example:



      $ split 'a;b;c' ';' | cat -n
      1 a
      2 b
      3 c


      Compared to the other solutions given, this one has the following advantages:




      • IFS is not overriden: Due to dynamic scoping of even local variables, overriding IFS over a loop causes the new value to leak into function calls performed from within the loop.


      • Arrays are not used: Reading a string into an array using read requires the flag -a in Bash and -A in zsh.



      If desired, the function may be put into a script as follows:



      #!/usr/bin/env bash

      split() {
      # ...
      }

      split "$@"





      share|improve this answer























      • works and neatly modularized.
        – sandeepkunkunuru
        Oct 23 '17 at 16:10


















      up vote
      4
      down vote













      This is the simplest way to do it.



      spo='one;two;three'
      OIFS=$IFS
      IFS=';'
      spo_array=($spo)
      IFS=$OIFS
      echo ${spo_array[*]}





      share|improve this answer






























        up vote
        3
        down vote













        IN="bla@some.com;john@home.com"
        IFS=';'
        read -a IN_arr <<< "${IN}"
        for entry in "${IN_arr[@]}"
        do
        echo $entry
        done


        Output



        bla@some.com
        john@home.com


        System : Ubuntu 12.04.1






        share|improve this answer























        • IFS is not getting set in the specific context of read here and hence it can upset rest of the code, if any.
          – codeforester
          Jan 2 '17 at 5:37


















        up vote
        3
        down vote













        you can apply awk to many situations



        echo "bla@some.com;john@home.com"|awk -F';' '{printf "%sn%sn", $1, $2}'


        also you can use this



        echo "bla@some.com;john@home.com"|awk -F';' '{print $1,$2}' OFS="n"





        share|improve this answer






























          up vote
          2
          down vote













          If no space, Why not this?



          IN="bla@some.com;john@home.com"
          arr=(`echo $IN | tr ';' ' '`)

          echo ${arr[0]}
          echo ${arr[1]}





          share|improve this answer




























            up vote
            2
            down vote













            Two bourne-ish alternatives where neither require bash arrays:



            Case 1: Keep it nice and simple: Use a NewLine as the Record-Separator... eg.



            IN="bla@some.com
            john@home.com"

            while read i; do
            # process "$i" ... eg.
            echo "[email:$i]"
            done <<< "$IN"


            Note: in this first case no sub-process is forked to assist with list manipulation.



            Idea: Maybe it is worth using NL extensively internally, and only converting to a different RS when generating the final result externally.



            Case 2: Using a ";" as a record separator... eg.



            NL="
            " IRS=";" ORS=";"

            conv_IRS() {
            exec tr "$1" "$NL"
            }

            conv_ORS() {
            exec tr "$NL" "$1"
            }

            IN="bla@some.com;john@home.com"
            IN="$(conv_IRS ";" <<< "$IN")"

            while read i; do
            # process "$i" ... eg.
            echo -n "[email:$i]$ORS"
            done <<< "$IN"


            In both cases a sub-list can be composed within the loop is persistent after the loop has completed. This is useful when manipulating lists in memory, instead storing lists in files. {p.s. keep calm and carry on B-) }






            share|improve this answer






























              up vote
              2
              down vote













              There are some cool answers here (errator esp.), but for something analogous to split in other languages -- which is what I took the original question to mean -- I settled on this:



              IN="bla@some.com;john@home.com"
              declare -a a="(${IN/;/ })";


              Now ${a[0]}, ${a[1]}, etc, are as you would expect. Use ${#a[*]} for number of terms. Or to iterate, of course:



              for i in ${a[*]}; do echo $i; done


              IMPORTANT NOTE:



              This works in cases where there are no spaces to worry about, which solved my problem, but may not solve yours. Go with the $IFS solution(s) in that case.






              share|improve this answer























              • Does not work when IN contains more than two e-mail addresses. Please refer to same idea (but fixed) at palindrom's answer
                – olibre
                Oct 7 '13 at 13:33












              • Better use ${IN//;/ } (double slash) to make it also work with more than two values. Beware that any wildcard (*?[) will be expanded. And a trailing empty field will be discarded.
                – sorontar
                Oct 26 '16 at 5:14


















              up vote
              1
              down vote













              Use the set built-in to load up the $@ array:



              IN="bla@some.com;john@home.com"
              IFS=';'; set $IN; IFS=$' tn'


              Then, let the party begin:



              echo $#
              for a; do echo $a; done
              ADDR1=$1 ADDR2=$2





              share|improve this answer





















              • Better use set -- $IN to avoid some issues with "$IN" starting with dash. Still, the unquoted expansion of $IN will expand wildcards (*?[).
                – sorontar
                Oct 26 '16 at 5:17


















              up vote
              1
              down vote













              Apart from the fantastic answers that were already provided, if it is just a matter of printing out the data you may consider using awk:



              awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]n", $i)}' <<< "$IN"


              This sets the field separator to ;, so that it can loop through the fields with a for loop and print accordingly.



              Test



              $ IN="bla@some.com;john@home.com"
              $ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]n", $i)}' <<< "$IN"
              > [bla@some.com]
              > [john@home.com]


              With another input:



              $ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]n", $i)}' <<< "a;b;c   d;e_;f"
              > [a]
              > [b]
              > [c d]
              > [e_]
              > [f]





              share|improve this answer




























                up vote
                1
                down vote













                In Android shell, most of the proposed methods just do not work:



                $ IFS=':' read -ra ADDR <<<"$PATH"                             
                /system/bin/sh: can't create temporary file /sqlite_stmt_journals/mksh.EbNoR10629: No such file or directory


                What does work is:



                $ for i in ${PATH//:/ }; do echo $i; done
                /sbin
                /vendor/bin
                /system/sbin
                /system/bin
                /system/xbin


                where // means global replacement.






                share|improve this answer



















                • 1




                  Fails if any part of $PATH contains spaces (or newlines). Also expands wildcards (asterisk *, question mark ? and braces […]).
                  – sorontar
                  Oct 26 '16 at 5:08


















                up vote
                1
                down vote













                Okay guys!



                Here's my answer!



                DELIMITER_VAL='='

                read -d '' F_ABOUT_DISTRO_R <<"EOF"
                DISTRIB_ID=Ubuntu
                DISTRIB_RELEASE=14.04
                DISTRIB_CODENAME=trusty
                DISTRIB_DESCRIPTION="Ubuntu 14.04.4 LTS"
                NAME="Ubuntu"
                VERSION="14.04.4 LTS, Trusty Tahr"
                ID=ubuntu
                ID_LIKE=debian
                PRETTY_NAME="Ubuntu 14.04.4 LTS"
                VERSION_ID="14.04"
                HOME_URL="http://www.ubuntu.com/"
                SUPPORT_URL="http://help.ubuntu.com/"
                BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
                EOF

                SPLIT_NOW=$(awk -F$DELIMITER_VAL '{for(i=1;i<=NF;i++){printf "%sn", $i}}' <<<"${F_ABOUT_DISTRO_R}")
                while read -r line; do
                SPLIT+=("$line")
                done <<< "$SPLIT_NOW"
                for i in "${SPLIT[@]}"; do
                echo "$i"
                done


                Why this approach is "the best" for me?



                Because of two reasons:




                1. You do not need to escape the delimiter;

                2. You will not have problem with blank spaces. The value will be properly separated in the array!


                's






                share|improve this answer























                • FYI, /etc/os-release and /etc/lsb-release are meant to be sourced, and not parsed. So your method is really wrong. Moreover, you're not quite answering the question about spiltting a string on a delimiter.
                  – gniourf_gniourf
                  Jan 30 '17 at 8:26




















                up vote
                0
                down vote













                A one-liner to split a string separated by ';' into an array is:



                IN="bla@some.com;john@home.com"
                ADDRS=( $(IFS=";" echo "$IN") )
                echo ${ADDRS[0]}
                echo ${ADDRS[1]}


                This only sets IFS in a subshell, so you don't have to worry about saving and restoring its value.






                share|improve this answer























                • -1 this doesn't work here (ubuntu 12.04). it prints only the first echo with all $IN value in it, while the second is empty. you can see it if you put echo "0: "${ADDRS[0]}n echo "1: "${ADDRS[1]} the output is0: bla@some.com;john@home.comn 1: (n is new line)
                  – Luca Borrione
                  Sep 3 '12 at 10:04






                • 1




                  please refer to nickjb's answer at for a working alternative to this idea stackoverflow.com/a/6583589/1032370
                  – Luca Borrione
                  Sep 3 '12 at 10:05






                • 1




                  -1, 1. IFS isn't being set in that subshell (it's being passed to the environment of "echo", which is a builtin, so nothing is happening anyway). 2. $IN is quoted so it isn't subject to IFS splitting. 3. The process substitution is split by whitespace, but this may corrupt the original data.
                  – Score_Under
                  Apr 28 '15 at 17:09




















                up vote
                0
                down vote













                IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/(){}*? are no problem;simple is beautiful :-)'
                set -f
                oldifs="$IFS"
                IFS=';'; arrayIN=($IN)
                IFS="$oldifs"
                for i in "${arrayIN[@]}"; do
                echo "$i"
                done
                set +f


                Output:



                bla@some.com
                john@home.com
                Charlie Brown <cbrown@acme.com
                !"#$%&/(){}*? are no problem
                simple is beautiful :-)


                Explanation: Simple assignment using parenthesis () converts semicolon separated list into an array provided you have correct IFS while doing that. Standard FOR loop handles individual items in that array as usual.
                Notice that the list given for IN variable must be "hard" quoted, that is, with single ticks.



                IFS must be saved and restored since Bash does not treat an assignment the same way as a command. An alternate workaround is to wrap the assignment inside a function and call that function with a modified IFS. In that case separate saving/restoring of IFS is not needed. Thanks for "Bize" for pointing that out.






                share|improve this answer























                • !"#$%&/(){}*? are no problem well... not quite: *? are glob characters. So what about creating this directory and file: `mkdir '!"#$%&'; touch '!"#$%&/(){} got you hahahaha - are no problem' and running your command? simple may be beautiful, but when it's broken, it's broken.
                  – gniourf_gniourf
                  Feb 20 '15 at 16:45










                • @gniourf_gniourf The string is stored in a variable. Please see the original question.
                  – ajaaskel
                  Feb 25 '15 at 7:20








                • 1




                  @ajaaskel you didn't fully understand my comment. Go in a scratch directory and issue these commands: mkdir '!"#$%&'; touch '!"#$%&/(){} got you hahahaha - are no problem'. They will only create a directory and a file, with weird looking names, I must admit. Then run your commands with the exact IN you gave: IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/(){}*? are no problem;simple is beautiful :-)'. You'll see that you won't get the output you expect. Because you're using a method subject to pathname expansions to split your string.
                  – gniourf_gniourf
                  Feb 25 '15 at 7:26












                • This is to demonstrate that the characters *, ?, [...] and even, if extglob is set, !(...), @(...), ?(...), +(...) are problems with this method!
                  – gniourf_gniourf
                  Feb 25 '15 at 7:29






                • 1




                  @gniourf_gniourf Thanks for detailed comments on globbing. I adjusted the code to have globbing off. My point was however just to show that rather simple assignment can do the splitting job.
                  – ajaaskel
                  Feb 26 '15 at 15:26




















                up vote
                0
                down vote













                Maybe not the most elegant solution, but works with * and spaces:



                IN="bla@so me.com;*;john@home.com"
                for i in `delims=${IN//[^;]}; seq 1 $((${#delims} + 1))`
                do
                echo "> [`echo $IN | cut -d';' -f$i`]"
                done


                Outputs



                > [bla@so me.com]
                > [*]
                > [john@home.com]


                Other example (delimiters at beginning and end):



                IN=";bla@so me.com;*;john@home.com;"
                >
                > [bla@so me.com]
                > [*]
                > [john@home.com]
                >


                Basically it removes every character other than ; making delims eg. ;;;. Then it does for loop from 1 to number-of-delimiters as counted by ${#delims}. The final step is to safely get the $ith part using cut.






                share|improve this answer

























                  1 2
                  next


                  protected by Jorgesys Dec 19 '13 at 21:39



                  Thank you for your interest in this question.
                  Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



                  Would you like to answer one of these unanswered questions instead?














                  33 Answers
                  33






                  active

                  oldest

                  votes








                  33 Answers
                  33






                  active

                  oldest

                  votes









                  active

                  oldest

                  votes






                  active

                  oldest

                  votes








                  1 2
                  next









                  up vote
                  978
                  down vote



                  accepted










                  You can set the internal field separator (IFS) variable, and then let it parse into an array. When this happens in a command, then the assignment to IFS only takes place to that single command's environment (to read ). It then parses the input according to the IFS variable value into an array, which we can then iterate over.



                  IFS=';' read -ra ADDR <<< "$IN"
                  for i in "${ADDR[@]}"; do
                  # process "$i"
                  done


                  It will parse one line of items separated by ;, pushing it into an array. Stuff for processing whole of $IN, each time one line of input separated by ;:



                   while IFS=';' read -ra ADDR; do
                  for i in "${ADDR[@]}"; do
                  # process "$i"
                  done
                  done <<< "$IN"





                  share|improve this answer



















                  • 16




                    This is probably the best way. How long will IFS persist in it's current value, can it mess up my code by being set when it shouldn't be, and how can I reset it when I'm done with it?
                    – Chris Lutz
                    May 28 '09 at 2:25






                  • 6




                    now after the fix applied, only within the duration of the read command :)
                    – Johannes Schaub - litb
                    May 28 '09 at 3:04






                  • 14




                    You can read everything at once without using a while loop: read -r -d '' -a addr <<< "$in" # The -d '' is key here, it tells read not to stop at the first newline (which is the default -d) but to continue until EOF or a NULL byte (which only occur in binary data).
                    – lhunath
                    May 28 '09 at 6:14






                  • 39




                    @LucaBorrione Setting IFS on the same line as the read with no semicolon or other separator, as opposed to in a separate command, scopes it to that command -- so it's always "restored"; you don't need to do anything manually.
                    – Charles Duffy
                    Jul 6 '13 at 14:39








                  • 5




                    @imagineerThis There is a bug involving herestrings and local changes to IFS that requires $IN to be quoted. The bug is fixed in bash 4.3.
                    – chepner
                    Oct 2 '14 at 3:50















                  up vote
                  978
                  down vote



                  accepted










                  You can set the internal field separator (IFS) variable, and then let it parse into an array. When this happens in a command, then the assignment to IFS only takes place to that single command's environment (to read ). It then parses the input according to the IFS variable value into an array, which we can then iterate over.



                  IFS=';' read -ra ADDR <<< "$IN"
                  for i in "${ADDR[@]}"; do
                  # process "$i"
                  done


                  It will parse one line of items separated by ;, pushing it into an array. Stuff for processing whole of $IN, each time one line of input separated by ;:



                   while IFS=';' read -ra ADDR; do
                  for i in "${ADDR[@]}"; do
                  # process "$i"
                  done
                  done <<< "$IN"





                  share|improve this answer



















                  • 16




                    This is probably the best way. How long will IFS persist in it's current value, can it mess up my code by being set when it shouldn't be, and how can I reset it when I'm done with it?
                    – Chris Lutz
                    May 28 '09 at 2:25






                  • 6




                    now after the fix applied, only within the duration of the read command :)
                    – Johannes Schaub - litb
                    May 28 '09 at 3:04






                  • 14




                    You can read everything at once without using a while loop: read -r -d '' -a addr <<< "$in" # The -d '' is key here, it tells read not to stop at the first newline (which is the default -d) but to continue until EOF or a NULL byte (which only occur in binary data).
                    – lhunath
                    May 28 '09 at 6:14






                  • 39




                    @LucaBorrione Setting IFS on the same line as the read with no semicolon or other separator, as opposed to in a separate command, scopes it to that command -- so it's always "restored"; you don't need to do anything manually.
                    – Charles Duffy
                    Jul 6 '13 at 14:39








                  • 5




                    @imagineerThis There is a bug involving herestrings and local changes to IFS that requires $IN to be quoted. The bug is fixed in bash 4.3.
                    – chepner
                    Oct 2 '14 at 3:50













                  up vote
                  978
                  down vote



                  accepted







                  up vote
                  978
                  down vote



                  accepted






                  You can set the internal field separator (IFS) variable, and then let it parse into an array. When this happens in a command, then the assignment to IFS only takes place to that single command's environment (to read ). It then parses the input according to the IFS variable value into an array, which we can then iterate over.



                  IFS=';' read -ra ADDR <<< "$IN"
                  for i in "${ADDR[@]}"; do
                  # process "$i"
                  done


                  It will parse one line of items separated by ;, pushing it into an array. Stuff for processing whole of $IN, each time one line of input separated by ;:



                   while IFS=';' read -ra ADDR; do
                  for i in "${ADDR[@]}"; do
                  # process "$i"
                  done
                  done <<< "$IN"





                  share|improve this answer














                  You can set the internal field separator (IFS) variable, and then let it parse into an array. When this happens in a command, then the assignment to IFS only takes place to that single command's environment (to read ). It then parses the input according to the IFS variable value into an array, which we can then iterate over.



                  IFS=';' read -ra ADDR <<< "$IN"
                  for i in "${ADDR[@]}"; do
                  # process "$i"
                  done


                  It will parse one line of items separated by ;, pushing it into an array. Stuff for processing whole of $IN, each time one line of input separated by ;:



                   while IFS=';' read -ra ADDR; do
                  for i in "${ADDR[@]}"; do
                  # process "$i"
                  done
                  done <<< "$IN"






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Mar 8 '12 at 20:31









                  Peter Mortensen

                  13.3k1983111




                  13.3k1983111










                  answered May 28 '09 at 2:23









                  Johannes Schaub - litb

                  402k977701106




                  402k977701106








                  • 16




                    This is probably the best way. How long will IFS persist in it's current value, can it mess up my code by being set when it shouldn't be, and how can I reset it when I'm done with it?
                    – Chris Lutz
                    May 28 '09 at 2:25






                  • 6




                    now after the fix applied, only within the duration of the read command :)
                    – Johannes Schaub - litb
                    May 28 '09 at 3:04






                  • 14




                    You can read everything at once without using a while loop: read -r -d '' -a addr <<< "$in" # The -d '' is key here, it tells read not to stop at the first newline (which is the default -d) but to continue until EOF or a NULL byte (which only occur in binary data).
                    – lhunath
                    May 28 '09 at 6:14






                  • 39




                    @LucaBorrione Setting IFS on the same line as the read with no semicolon or other separator, as opposed to in a separate command, scopes it to that command -- so it's always "restored"; you don't need to do anything manually.
                    – Charles Duffy
                    Jul 6 '13 at 14:39








                  • 5




                    @imagineerThis There is a bug involving herestrings and local changes to IFS that requires $IN to be quoted. The bug is fixed in bash 4.3.
                    – chepner
                    Oct 2 '14 at 3:50














                  • 16




                    This is probably the best way. How long will IFS persist in it's current value, can it mess up my code by being set when it shouldn't be, and how can I reset it when I'm done with it?
                    – Chris Lutz
                    May 28 '09 at 2:25






                  • 6




                    now after the fix applied, only within the duration of the read command :)
                    – Johannes Schaub - litb
                    May 28 '09 at 3:04






                  • 14




                    You can read everything at once without using a while loop: read -r -d '' -a addr <<< "$in" # The -d '' is key here, it tells read not to stop at the first newline (which is the default -d) but to continue until EOF or a NULL byte (which only occur in binary data).
                    – lhunath
                    May 28 '09 at 6:14






                  • 39




                    @LucaBorrione Setting IFS on the same line as the read with no semicolon or other separator, as opposed to in a separate command, scopes it to that command -- so it's always "restored"; you don't need to do anything manually.
                    – Charles Duffy
                    Jul 6 '13 at 14:39








                  • 5




                    @imagineerThis There is a bug involving herestrings and local changes to IFS that requires $IN to be quoted. The bug is fixed in bash 4.3.
                    – chepner
                    Oct 2 '14 at 3:50








                  16




                  16




                  This is probably the best way. How long will IFS persist in it's current value, can it mess up my code by being set when it shouldn't be, and how can I reset it when I'm done with it?
                  – Chris Lutz
                  May 28 '09 at 2:25




                  This is probably the best way. How long will IFS persist in it's current value, can it mess up my code by being set when it shouldn't be, and how can I reset it when I'm done with it?
                  – Chris Lutz
                  May 28 '09 at 2:25




                  6




                  6




                  now after the fix applied, only within the duration of the read command :)
                  – Johannes Schaub - litb
                  May 28 '09 at 3:04




                  now after the fix applied, only within the duration of the read command :)
                  – Johannes Schaub - litb
                  May 28 '09 at 3:04




                  14




                  14




                  You can read everything at once without using a while loop: read -r -d '' -a addr <<< "$in" # The -d '' is key here, it tells read not to stop at the first newline (which is the default -d) but to continue until EOF or a NULL byte (which only occur in binary data).
                  – lhunath
                  May 28 '09 at 6:14




                  You can read everything at once without using a while loop: read -r -d '' -a addr <<< "$in" # The -d '' is key here, it tells read not to stop at the first newline (which is the default -d) but to continue until EOF or a NULL byte (which only occur in binary data).
                  – lhunath
                  May 28 '09 at 6:14




                  39




                  39




                  @LucaBorrione Setting IFS on the same line as the read with no semicolon or other separator, as opposed to in a separate command, scopes it to that command -- so it's always "restored"; you don't need to do anything manually.
                  – Charles Duffy
                  Jul 6 '13 at 14:39






                  @LucaBorrione Setting IFS on the same line as the read with no semicolon or other separator, as opposed to in a separate command, scopes it to that command -- so it's always "restored"; you don't need to do anything manually.
                  – Charles Duffy
                  Jul 6 '13 at 14:39






                  5




                  5




                  @imagineerThis There is a bug involving herestrings and local changes to IFS that requires $IN to be quoted. The bug is fixed in bash 4.3.
                  – chepner
                  Oct 2 '14 at 3:50




                  @imagineerThis There is a bug involving herestrings and local changes to IFS that requires $IN to be quoted. The bug is fixed in bash 4.3.
                  – chepner
                  Oct 2 '14 at 3:50












                  up vote
                  787
                  down vote













                  Taken from Bash shell script split array:



                  IN="bla@some.com;john@home.com"
                  arrIN=(${IN//;/ })


                  Explanation:



                  This construction replaces all occurrences of ';' (the initial // means global replace) in the string IN with ' ' (a single space), then interprets the space-delimited string as an array (that's what the surrounding parentheses do).



                  The syntax used inside of the curly braces to replace each ';' character with a ' ' character is called Parameter Expansion.



                  There are some common gotchas:




                  1. If the original string has spaces, you will need to use IFS:


                    • IFS=':'; arrIN=($IN); unset IFS;



                  2. If the original string has spaces and the delimiter is a new line, you can set IFS with:


                    • IFS=$'n'; arrIN=($IN); unset IFS;








                  share|improve this answer



















                  • 70




                    I just want to add: this is the simplest of all, you can access array elements with ${arrIN[1]} (starting from zeros of course)
                    – Oz123
                    Mar 21 '11 at 18:50






                  • 23




                    Found it: the technique of modifying a variable within a ${} is known as 'parameter expansion'.
                    – KomodoDave
                    Jan 5 '12 at 15:13






                  • 23




                    Does it work when the original string contains spaces?
                    – qbolec
                    Feb 25 '13 at 9:12






                  • 21




                    No, I don't think this works when there are also spaces present... it's converting the ',' to ' ' and then building a space-separated array.
                    – Ethan
                    Apr 12 '13 at 22:47






                  • 41




                    This is a bad approach for other reasons: For instance, if your string contains ;*;, then the * will be expanded to a list of filenames in the current directory. -1
                    – Charles Duffy
                    Jul 6 '13 at 14:39















                  up vote
                  787
                  down vote













                  Taken from Bash shell script split array:



                  IN="bla@some.com;john@home.com"
                  arrIN=(${IN//;/ })


                  Explanation:



                  This construction replaces all occurrences of ';' (the initial // means global replace) in the string IN with ' ' (a single space), then interprets the space-delimited string as an array (that's what the surrounding parentheses do).



                  The syntax used inside of the curly braces to replace each ';' character with a ' ' character is called Parameter Expansion.



                  There are some common gotchas:




                  1. If the original string has spaces, you will need to use IFS:


                    • IFS=':'; arrIN=($IN); unset IFS;



                  2. If the original string has spaces and the delimiter is a new line, you can set IFS with:


                    • IFS=$'n'; arrIN=($IN); unset IFS;








                  share|improve this answer



















                  • 70




                    I just want to add: this is the simplest of all, you can access array elements with ${arrIN[1]} (starting from zeros of course)
                    – Oz123
                    Mar 21 '11 at 18:50






                  • 23




                    Found it: the technique of modifying a variable within a ${} is known as 'parameter expansion'.
                    – KomodoDave
                    Jan 5 '12 at 15:13






                  • 23




                    Does it work when the original string contains spaces?
                    – qbolec
                    Feb 25 '13 at 9:12






                  • 21




                    No, I don't think this works when there are also spaces present... it's converting the ',' to ' ' and then building a space-separated array.
                    – Ethan
                    Apr 12 '13 at 22:47






                  • 41




                    This is a bad approach for other reasons: For instance, if your string contains ;*;, then the * will be expanded to a list of filenames in the current directory. -1
                    – Charles Duffy
                    Jul 6 '13 at 14:39













                  up vote
                  787
                  down vote










                  up vote
                  787
                  down vote









                  Taken from Bash shell script split array:



                  IN="bla@some.com;john@home.com"
                  arrIN=(${IN//;/ })


                  Explanation:



                  This construction replaces all occurrences of ';' (the initial // means global replace) in the string IN with ' ' (a single space), then interprets the space-delimited string as an array (that's what the surrounding parentheses do).



                  The syntax used inside of the curly braces to replace each ';' character with a ' ' character is called Parameter Expansion.



                  There are some common gotchas:




                  1. If the original string has spaces, you will need to use IFS:


                    • IFS=':'; arrIN=($IN); unset IFS;



                  2. If the original string has spaces and the delimiter is a new line, you can set IFS with:


                    • IFS=$'n'; arrIN=($IN); unset IFS;








                  share|improve this answer














                  Taken from Bash shell script split array:



                  IN="bla@some.com;john@home.com"
                  arrIN=(${IN//;/ })


                  Explanation:



                  This construction replaces all occurrences of ';' (the initial // means global replace) in the string IN with ' ' (a single space), then interprets the space-delimited string as an array (that's what the surrounding parentheses do).



                  The syntax used inside of the curly braces to replace each ';' character with a ' ' character is called Parameter Expansion.



                  There are some common gotchas:




                  1. If the original string has spaces, you will need to use IFS:


                    • IFS=':'; arrIN=($IN); unset IFS;



                  2. If the original string has spaces and the delimiter is a new line, you can set IFS with:


                    • IFS=$'n'; arrIN=($IN); unset IFS;









                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Apr 13 '17 at 12:36









                  Community

                  11




                  11










                  answered Mar 10 '11 at 9:00









                  palindrom

                  9,28611323




                  9,28611323








                  • 70




                    I just want to add: this is the simplest of all, you can access array elements with ${arrIN[1]} (starting from zeros of course)
                    – Oz123
                    Mar 21 '11 at 18:50






                  • 23




                    Found it: the technique of modifying a variable within a ${} is known as 'parameter expansion'.
                    – KomodoDave
                    Jan 5 '12 at 15:13






                  • 23




                    Does it work when the original string contains spaces?
                    – qbolec
                    Feb 25 '13 at 9:12






                  • 21




                    No, I don't think this works when there are also spaces present... it's converting the ',' to ' ' and then building a space-separated array.
                    – Ethan
                    Apr 12 '13 at 22:47






                  • 41




                    This is a bad approach for other reasons: For instance, if your string contains ;*;, then the * will be expanded to a list of filenames in the current directory. -1
                    – Charles Duffy
                    Jul 6 '13 at 14:39














                  • 70




                    I just want to add: this is the simplest of all, you can access array elements with ${arrIN[1]} (starting from zeros of course)
                    – Oz123
                    Mar 21 '11 at 18:50






                  • 23




                    Found it: the technique of modifying a variable within a ${} is known as 'parameter expansion'.
                    – KomodoDave
                    Jan 5 '12 at 15:13






                  • 23




                    Does it work when the original string contains spaces?
                    – qbolec
                    Feb 25 '13 at 9:12






                  • 21




                    No, I don't think this works when there are also spaces present... it's converting the ',' to ' ' and then building a space-separated array.
                    – Ethan
                    Apr 12 '13 at 22:47






                  • 41




                    This is a bad approach for other reasons: For instance, if your string contains ;*;, then the * will be expanded to a list of filenames in the current directory. -1
                    – Charles Duffy
                    Jul 6 '13 at 14:39








                  70




                  70




                  I just want to add: this is the simplest of all, you can access array elements with ${arrIN[1]} (starting from zeros of course)
                  – Oz123
                  Mar 21 '11 at 18:50




                  I just want to add: this is the simplest of all, you can access array elements with ${arrIN[1]} (starting from zeros of course)
                  – Oz123
                  Mar 21 '11 at 18:50




                  23




                  23




                  Found it: the technique of modifying a variable within a ${} is known as 'parameter expansion'.
                  – KomodoDave
                  Jan 5 '12 at 15:13




                  Found it: the technique of modifying a variable within a ${} is known as 'parameter expansion'.
                  – KomodoDave
                  Jan 5 '12 at 15:13




                  23




                  23




                  Does it work when the original string contains spaces?
                  – qbolec
                  Feb 25 '13 at 9:12




                  Does it work when the original string contains spaces?
                  – qbolec
                  Feb 25 '13 at 9:12




                  21




                  21




                  No, I don't think this works when there are also spaces present... it's converting the ',' to ' ' and then building a space-separated array.
                  – Ethan
                  Apr 12 '13 at 22:47




                  No, I don't think this works when there are also spaces present... it's converting the ',' to ' ' and then building a space-separated array.
                  – Ethan
                  Apr 12 '13 at 22:47




                  41




                  41




                  This is a bad approach for other reasons: For instance, if your string contains ;*;, then the * will be expanded to a list of filenames in the current directory. -1
                  – Charles Duffy
                  Jul 6 '13 at 14:39




                  This is a bad approach for other reasons: For instance, if your string contains ;*;, then the * will be expanded to a list of filenames in the current directory. -1
                  – Charles Duffy
                  Jul 6 '13 at 14:39










                  up vote
                  215
                  down vote













                  If you don't mind processing them immediately, I like to do this:



                  for i in $(echo $IN | tr ";" "n")
                  do
                  # process
                  done


                  You could use this kind of loop to initialize an array, but there's probably an easier way to do it. Hope this helps, though.






                  share|improve this answer





















                  • You should have kept the IFS answer. It taught me something I didn't know, and it definitely made an array, whereas this just makes a cheap substitute.
                    – Chris Lutz
                    May 28 '09 at 2:42










                  • I see. Yeah i find doing these silly experiments, i'm going to learn new things each time i'm trying to answer things. I've edited stuff based on #bash IRC feedback and undeleted :)
                    – Johannes Schaub - litb
                    May 28 '09 at 2:59






                  • 31




                    -1, you're obviously not aware of wordsplitting, because it's introducing two bugs in your code. one is when you don't quote $IN and the other is when you pretend a newline is the only delimiter used in wordsplitting. You are iterating over every WORD in IN, not every line, and DEFINATELY not every element delimited by a semicolon, though it may appear to have the side-effect of looking like it works.
                    – lhunath
                    May 28 '09 at 6:12






                  • 2




                    You could change it to echo "$IN" | tr ';' 'n' | while read -r ADDY; do # process "$ADDY"; done to make him lucky, i think :) Note that this will fork, and you can't change outer variables from within the loop (that's why i used the <<< "$IN" syntax) then
                    – Johannes Schaub - litb
                    May 28 '09 at 17:00






                  • 7




                    To summarize the debate in the comments: Caveats for general use: the shell applies word splitting and expansions to the string, which may be undesired; just try it with. IN="bla@some.com;john@home.com;*;broken apart". In short: this approach will break, if your tokens contain embedded spaces and/or chars. such as * that happen to make a token match filenames in the current folder.
                    – mklement0
                    Apr 24 '13 at 14:13















                  up vote
                  215
                  down vote













                  If you don't mind processing them immediately, I like to do this:



                  for i in $(echo $IN | tr ";" "n")
                  do
                  # process
                  done


                  You could use this kind of loop to initialize an array, but there's probably an easier way to do it. Hope this helps, though.






                  share|improve this answer





















                  • You should have kept the IFS answer. It taught me something I didn't know, and it definitely made an array, whereas this just makes a cheap substitute.
                    – Chris Lutz
                    May 28 '09 at 2:42










                  • I see. Yeah i find doing these silly experiments, i'm going to learn new things each time i'm trying to answer things. I've edited stuff based on #bash IRC feedback and undeleted :)
                    – Johannes Schaub - litb
                    May 28 '09 at 2:59






                  • 31




                    -1, you're obviously not aware of wordsplitting, because it's introducing two bugs in your code. one is when you don't quote $IN and the other is when you pretend a newline is the only delimiter used in wordsplitting. You are iterating over every WORD in IN, not every line, and DEFINATELY not every element delimited by a semicolon, though it may appear to have the side-effect of looking like it works.
                    – lhunath
                    May 28 '09 at 6:12






                  • 2




                    You could change it to echo "$IN" | tr ';' 'n' | while read -r ADDY; do # process "$ADDY"; done to make him lucky, i think :) Note that this will fork, and you can't change outer variables from within the loop (that's why i used the <<< "$IN" syntax) then
                    – Johannes Schaub - litb
                    May 28 '09 at 17:00






                  • 7




                    To summarize the debate in the comments: Caveats for general use: the shell applies word splitting and expansions to the string, which may be undesired; just try it with. IN="bla@some.com;john@home.com;*;broken apart". In short: this approach will break, if your tokens contain embedded spaces and/or chars. such as * that happen to make a token match filenames in the current folder.
                    – mklement0
                    Apr 24 '13 at 14:13













                  up vote
                  215
                  down vote










                  up vote
                  215
                  down vote









                  If you don't mind processing them immediately, I like to do this:



                  for i in $(echo $IN | tr ";" "n")
                  do
                  # process
                  done


                  You could use this kind of loop to initialize an array, but there's probably an easier way to do it. Hope this helps, though.






                  share|improve this answer












                  If you don't mind processing them immediately, I like to do this:



                  for i in $(echo $IN | tr ";" "n")
                  do
                  # process
                  done


                  You could use this kind of loop to initialize an array, but there's probably an easier way to do it. Hope this helps, though.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered May 28 '09 at 2:09









                  Chris Lutz

                  53.5k13110172




                  53.5k13110172












                  • You should have kept the IFS answer. It taught me something I didn't know, and it definitely made an array, whereas this just makes a cheap substitute.
                    – Chris Lutz
                    May 28 '09 at 2:42










                  • I see. Yeah i find doing these silly experiments, i'm going to learn new things each time i'm trying to answer things. I've edited stuff based on #bash IRC feedback and undeleted :)
                    – Johannes Schaub - litb
                    May 28 '09 at 2:59






                  • 31




                    -1, you're obviously not aware of wordsplitting, because it's introducing two bugs in your code. one is when you don't quote $IN and the other is when you pretend a newline is the only delimiter used in wordsplitting. You are iterating over every WORD in IN, not every line, and DEFINATELY not every element delimited by a semicolon, though it may appear to have the side-effect of looking like it works.
                    – lhunath
                    May 28 '09 at 6:12






                  • 2




                    You could change it to echo "$IN" | tr ';' 'n' | while read -r ADDY; do # process "$ADDY"; done to make him lucky, i think :) Note that this will fork, and you can't change outer variables from within the loop (that's why i used the <<< "$IN" syntax) then
                    – Johannes Schaub - litb
                    May 28 '09 at 17:00






                  • 7




                    To summarize the debate in the comments: Caveats for general use: the shell applies word splitting and expansions to the string, which may be undesired; just try it with. IN="bla@some.com;john@home.com;*;broken apart". In short: this approach will break, if your tokens contain embedded spaces and/or chars. such as * that happen to make a token match filenames in the current folder.
                    – mklement0
                    Apr 24 '13 at 14:13


















                  • You should have kept the IFS answer. It taught me something I didn't know, and it definitely made an array, whereas this just makes a cheap substitute.
                    – Chris Lutz
                    May 28 '09 at 2:42










                  • I see. Yeah i find doing these silly experiments, i'm going to learn new things each time i'm trying to answer things. I've edited stuff based on #bash IRC feedback and undeleted :)
                    – Johannes Schaub - litb
                    May 28 '09 at 2:59






                  • 31




                    -1, you're obviously not aware of wordsplitting, because it's introducing two bugs in your code. one is when you don't quote $IN and the other is when you pretend a newline is the only delimiter used in wordsplitting. You are iterating over every WORD in IN, not every line, and DEFINATELY not every element delimited by a semicolon, though it may appear to have the side-effect of looking like it works.
                    – lhunath
                    May 28 '09 at 6:12






                  • 2




                    You could change it to echo "$IN" | tr ';' 'n' | while read -r ADDY; do # process "$ADDY"; done to make him lucky, i think :) Note that this will fork, and you can't change outer variables from within the loop (that's why i used the <<< "$IN" syntax) then
                    – Johannes Schaub - litb
                    May 28 '09 at 17:00






                  • 7




                    To summarize the debate in the comments: Caveats for general use: the shell applies word splitting and expansions to the string, which may be undesired; just try it with. IN="bla@some.com;john@home.com;*;broken apart". In short: this approach will break, if your tokens contain embedded spaces and/or chars. such as * that happen to make a token match filenames in the current folder.
                    – mklement0
                    Apr 24 '13 at 14:13
















                  You should have kept the IFS answer. It taught me something I didn't know, and it definitely made an array, whereas this just makes a cheap substitute.
                  – Chris Lutz
                  May 28 '09 at 2:42




                  You should have kept the IFS answer. It taught me something I didn't know, and it definitely made an array, whereas this just makes a cheap substitute.
                  – Chris Lutz
                  May 28 '09 at 2:42












                  I see. Yeah i find doing these silly experiments, i'm going to learn new things each time i'm trying to answer things. I've edited stuff based on #bash IRC feedback and undeleted :)
                  – Johannes Schaub - litb
                  May 28 '09 at 2:59




                  I see. Yeah i find doing these silly experiments, i'm going to learn new things each time i'm trying to answer things. I've edited stuff based on #bash IRC feedback and undeleted :)
                  – Johannes Schaub - litb
                  May 28 '09 at 2:59




                  31




                  31




                  -1, you're obviously not aware of wordsplitting, because it's introducing two bugs in your code. one is when you don't quote $IN and the other is when you pretend a newline is the only delimiter used in wordsplitting. You are iterating over every WORD in IN, not every line, and DEFINATELY not every element delimited by a semicolon, though it may appear to have the side-effect of looking like it works.
                  – lhunath
                  May 28 '09 at 6:12




                  -1, you're obviously not aware of wordsplitting, because it's introducing two bugs in your code. one is when you don't quote $IN and the other is when you pretend a newline is the only delimiter used in wordsplitting. You are iterating over every WORD in IN, not every line, and DEFINATELY not every element delimited by a semicolon, though it may appear to have the side-effect of looking like it works.
                  – lhunath
                  May 28 '09 at 6:12




                  2




                  2




                  You could change it to echo "$IN" | tr ';' 'n' | while read -r ADDY; do # process "$ADDY"; done to make him lucky, i think :) Note that this will fork, and you can't change outer variables from within the loop (that's why i used the <<< "$IN" syntax) then
                  – Johannes Schaub - litb
                  May 28 '09 at 17:00




                  You could change it to echo "$IN" | tr ';' 'n' | while read -r ADDY; do # process "$ADDY"; done to make him lucky, i think :) Note that this will fork, and you can't change outer variables from within the loop (that's why i used the <<< "$IN" syntax) then
                  – Johannes Schaub - litb
                  May 28 '09 at 17:00




                  7




                  7




                  To summarize the debate in the comments: Caveats for general use: the shell applies word splitting and expansions to the string, which may be undesired; just try it with. IN="bla@some.com;john@home.com;*;broken apart". In short: this approach will break, if your tokens contain embedded spaces and/or chars. such as * that happen to make a token match filenames in the current folder.
                  – mklement0
                  Apr 24 '13 at 14:13




                  To summarize the debate in the comments: Caveats for general use: the shell applies word splitting and expansions to the string, which may be undesired; just try it with. IN="bla@some.com;john@home.com;*;broken apart". In short: this approach will break, if your tokens contain embedded spaces and/or chars. such as * that happen to make a token match filenames in the current folder.
                  – mklement0
                  Apr 24 '13 at 14:13










                  up vote
                  139
                  down vote













                  Compatible answer



                  To this SO question, there is already a lot of different way to do this in bash.
                  But bash has many special features, so called bashism that work well, but that won't work in any other shell.



                  In particular, arrays, associative array, and pattern substitution are pure bashisms and may not work under other shells.



                  On my Debian GNU/Linux, there is a standard shell called dash, but I know many people who like to use ksh.



                  Finally, in very small situation, there is a special tool called busybox with his own shell interpreter (ash).



                  Requested string



                  The string sample in SO question is:



                  IN="bla@some.com;john@home.com"


                  As this could be useful with whitespaces and as whitespaces could modify the result of the routine, I prefer to use this sample string:



                   IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"


                  Split string based on delimiter in bash (version >=4.2)



                  Under pure bash, we may use arrays and IFS:



                  var="bla@some.com;john@home.com;Full Name <fulnam@other.org>"




                  oIFS="$IFS"
                  IFS=";"
                  declare -a fields=($var)
                  IFS="$oIFS"
                  unset oIFS




                  IFS=; read -a fields <<<"$IN"


                  Using this syntax under recent bash don't change $IFS for current session, but only for the current command:



                  set | grep ^IFS=
                  IFS=$' tn'


                  Now the string var is split and stored into an array (named fields):



                  set | grep ^fields=\|^var=
                  fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")
                  var='bla@some.com;john@home.com;Full Name <fulnam@other.org>'


                  We could request for variable content with declare -p:



                  declare -p IN fields
                  declare -- IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
                  declare -a fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")


                  read is the quickiest way to do the split, because there is no forks and no external resources called.



                  From there, you could use the syntax you already know for processing each field:



                  for x in "${fields[@]}";do
                  echo "> [$x]"
                  done
                  > [bla@some.com]
                  > [john@home.com]
                  > [Full Name <fulnam@other.org>]


                  or drop each field after processing (I like this shifting approach):



                  while [ "$fields" ] ;do
                  echo "> [$fields]"
                  fields=("${fields[@]:1}")
                  done
                  > [bla@some.com]
                  > [john@home.com]
                  > [Full Name <fulnam@other.org>]


                  or even for simple printout (shorter syntax):



                  printf "> [%s]n" "${fields[@]}"
                  > [bla@some.com]
                  > [john@home.com]
                  > [Full Name <fulnam@other.org>]


                  Update: recent bash >= 4.4



                  You could play with mapfile:



                  mapfile -td ; fields < <(printf "%s" "$IN")


                  This syntax preserve special chars, newlines and empty fields!



                  If you don't care about empty fields, you could:



                  mapfile -td ; fields <<<"$IN"
                  fields=("${fields[@]%$'n'}") # drop 'n' added by '<<<'


                  But you could use fields through function:



                  myPubliMail() {
                  printf "Seq: %6d: Sending mail to '%s'..." $1 "$2"
                  # mail -s "This is not a spam..." "$2" </path/to/body
                  printf "e[3D, done.n"
                  }

                  mapfile < <(printf "%s" "$IN") -td ; -c 1 -C myPubliMail


                  (Nota: at end of format string are useless while you don't care about empty fields at end of string)



                  mapfile < <(echo -n "$IN") -td ; -c 1 -C myPubliMail


                  Will render something like:



                  Seq:      0: Sending mail to 'bla@some.com', done.
                  Seq: 1: Sending mail to 'john@home.com', done.
                  Seq: 2: Sending mail to 'Full Name <fulnam@other.org>', done.


                  Or Drop newline added by <<< bash syntax in function:



                  myPubliMail() {
                  local seq=$1 dest="${2%$'n'}"
                  printf "Seq: %6d: Sending mail to '%s'..." $seq "$dest"
                  # mail -s "This is not a spam..." "$dest" </path/to/body
                  printf "e[3D, done.n"
                  }

                  mapfile <<<"$IN" -td ; -c 1 -C myPubliMail


                  Will render same output:



                  Seq:      0: Sending mail to 'bla@some.com', done.
                  Seq: 1: Sending mail to 'john@home.com', done.
                  Seq: 2: Sending mail to 'Full Name <fulnam@other.org>', done.


                  Split string based on delimiter in shell



                  But if you would write something usable under many shells, you have to not use bashisms.



                  There is a syntax, used in many shells, for splitting a string across first or last occurrence of a substring:



                  ${var#*SubStr}  # will drop begin of string up to first occur of `SubStr`
                  ${var##*SubStr} # will drop begin of string up to last occur of `SubStr`
                  ${var%SubStr*} # will drop part of string from last occur of `SubStr` to the end
                  ${var%%SubStr*} # will drop part of string from first occur of `SubStr` to the end


                  (The missing of this is the main reason of my answer publication ;)



                  As pointed out by Score_Under:




                  # and % delete the shortest possible matching string, and



                  ## and %% delete the longest possible.



                  where # and ## mean from left (begin) of string, and



                  % and %% meand from right (end) of string.




                  This little sample script work well under bash, dash, ksh, busybox and was tested under Mac-OS's bash too:



                  var="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
                  while [ "$var" ] ;do
                  iter=${var%%;*}
                  echo "> [$iter]"
                  [ "$var" = "$iter" ] &&
                  var='' ||
                  var="${var#*;}"
                  done
                  > [bla@some.com]
                  > [john@home.com]
                  > [Full Name <fulnam@other.org>]


                  Have fun!






                  share|improve this answer



















                  • 11




                    The #, ##, %, and %% substitutions have what is IMO an easier explanation to remember (for how much they delete): # and % delete the shortest possible matching string, and ## and %% delete the longest possible.
                    – Score_Under
                    Apr 28 '15 at 16:58








                  • 1




                    The IFS=; read -a fields <<<"$var" fails on newlines and add a trailing newline. The other solution removes a trailing empty field.
                    – sorontar
                    Oct 26 '16 at 4:36










                  • The shell delimiter is the most elegant answer, period.
                    – Eric Chen
                    Aug 30 '17 at 17:50












                  • Could the last alternative be used with a list of field separators set somewhere else? For instance, I mean to use this as a shell script, and pass a list of field separators as a positional parameter.
                    – sancho.s
                    Oct 4 at 3:42










                  • Yes, in a loop: for sep in "#" "ł" "@" ; do ... var="${var#*$sep}" ...
                    – F. Hauri
                    Oct 4 at 7:47

















                  up vote
                  139
                  down vote













                  Compatible answer



                  To this SO question, there is already a lot of different way to do this in bash.
                  But bash has many special features, so called bashism that work well, but that won't work in any other shell.



                  In particular, arrays, associative array, and pattern substitution are pure bashisms and may not work under other shells.



                  On my Debian GNU/Linux, there is a standard shell called dash, but I know many people who like to use ksh.



                  Finally, in very small situation, there is a special tool called busybox with his own shell interpreter (ash).



                  Requested string



                  The string sample in SO question is:



                  IN="bla@some.com;john@home.com"


                  As this could be useful with whitespaces and as whitespaces could modify the result of the routine, I prefer to use this sample string:



                   IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"


                  Split string based on delimiter in bash (version >=4.2)



                  Under pure bash, we may use arrays and IFS:



                  var="bla@some.com;john@home.com;Full Name <fulnam@other.org>"




                  oIFS="$IFS"
                  IFS=";"
                  declare -a fields=($var)
                  IFS="$oIFS"
                  unset oIFS




                  IFS=; read -a fields <<<"$IN"


                  Using this syntax under recent bash don't change $IFS for current session, but only for the current command:



                  set | grep ^IFS=
                  IFS=$' tn'


                  Now the string var is split and stored into an array (named fields):



                  set | grep ^fields=\|^var=
                  fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")
                  var='bla@some.com;john@home.com;Full Name <fulnam@other.org>'


                  We could request for variable content with declare -p:



                  declare -p IN fields
                  declare -- IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
                  declare -a fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")


                  read is the quickiest way to do the split, because there is no forks and no external resources called.



                  From there, you could use the syntax you already know for processing each field:



                  for x in "${fields[@]}";do
                  echo "> [$x]"
                  done
                  > [bla@some.com]
                  > [john@home.com]
                  > [Full Name <fulnam@other.org>]


                  or drop each field after processing (I like this shifting approach):



                  while [ "$fields" ] ;do
                  echo "> [$fields]"
                  fields=("${fields[@]:1}")
                  done
                  > [bla@some.com]
                  > [john@home.com]
                  > [Full Name <fulnam@other.org>]


                  or even for simple printout (shorter syntax):



                  printf "> [%s]n" "${fields[@]}"
                  > [bla@some.com]
                  > [john@home.com]
                  > [Full Name <fulnam@other.org>]


                  Update: recent bash >= 4.4



                  You could play with mapfile:



                  mapfile -td ; fields < <(printf "%s" "$IN")


                  This syntax preserve special chars, newlines and empty fields!



                  If you don't care about empty fields, you could:



                  mapfile -td ; fields <<<"$IN"
                  fields=("${fields[@]%$'n'}") # drop 'n' added by '<<<'


                  But you could use fields through function:



                  myPubliMail() {
                  printf "Seq: %6d: Sending mail to '%s'..." $1 "$2"
                  # mail -s "This is not a spam..." "$2" </path/to/body
                  printf "e[3D, done.n"
                  }

                  mapfile < <(printf "%s" "$IN") -td ; -c 1 -C myPubliMail


                  (Nota: at end of format string are useless while you don't care about empty fields at end of string)



                  mapfile < <(echo -n "$IN") -td ; -c 1 -C myPubliMail


                  Will render something like:



                  Seq:      0: Sending mail to 'bla@some.com', done.
                  Seq: 1: Sending mail to 'john@home.com', done.
                  Seq: 2: Sending mail to 'Full Name <fulnam@other.org>', done.


                  Or Drop newline added by <<< bash syntax in function:



                  myPubliMail() {
                  local seq=$1 dest="${2%$'n'}"
                  printf "Seq: %6d: Sending mail to '%s'..." $seq "$dest"
                  # mail -s "This is not a spam..." "$dest" </path/to/body
                  printf "e[3D, done.n"
                  }

                  mapfile <<<"$IN" -td ; -c 1 -C myPubliMail


                  Will render same output:



                  Seq:      0: Sending mail to 'bla@some.com', done.
                  Seq: 1: Sending mail to 'john@home.com', done.
                  Seq: 2: Sending mail to 'Full Name <fulnam@other.org>', done.


                  Split string based on delimiter in shell



                  But if you would write something usable under many shells, you have to not use bashisms.



                  There is a syntax, used in many shells, for splitting a string across first or last occurrence of a substring:



                  ${var#*SubStr}  # will drop begin of string up to first occur of `SubStr`
                  ${var##*SubStr} # will drop begin of string up to last occur of `SubStr`
                  ${var%SubStr*} # will drop part of string from last occur of `SubStr` to the end
                  ${var%%SubStr*} # will drop part of string from first occur of `SubStr` to the end


                  (The missing of this is the main reason of my answer publication ;)



                  As pointed out by Score_Under:




                  # and % delete the shortest possible matching string, and



                  ## and %% delete the longest possible.



                  where # and ## mean from left (begin) of string, and



                  % and %% meand from right (end) of string.




                  This little sample script work well under bash, dash, ksh, busybox and was tested under Mac-OS's bash too:



                  var="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
                  while [ "$var" ] ;do
                  iter=${var%%;*}
                  echo "> [$iter]"
                  [ "$var" = "$iter" ] &&
                  var='' ||
                  var="${var#*;}"
                  done
                  > [bla@some.com]
                  > [john@home.com]
                  > [Full Name <fulnam@other.org>]


                  Have fun!






                  share|improve this answer



















                  • 11




                    The #, ##, %, and %% substitutions have what is IMO an easier explanation to remember (for how much they delete): # and % delete the shortest possible matching string, and ## and %% delete the longest possible.
                    – Score_Under
                    Apr 28 '15 at 16:58








                  • 1




                    The IFS=; read -a fields <<<"$var" fails on newlines and add a trailing newline. The other solution removes a trailing empty field.
                    – sorontar
                    Oct 26 '16 at 4:36










                  • The shell delimiter is the most elegant answer, period.
                    – Eric Chen
                    Aug 30 '17 at 17:50












                  • Could the last alternative be used with a list of field separators set somewhere else? For instance, I mean to use this as a shell script, and pass a list of field separators as a positional parameter.
                    – sancho.s
                    Oct 4 at 3:42










                  • Yes, in a loop: for sep in "#" "ł" "@" ; do ... var="${var#*$sep}" ...
                    – F. Hauri
                    Oct 4 at 7:47















                  up vote
                  139
                  down vote










                  up vote
                  139
                  down vote









                  Compatible answer



                  To this SO question, there is already a lot of different way to do this in bash.
                  But bash has many special features, so called bashism that work well, but that won't work in any other shell.



                  In particular, arrays, associative array, and pattern substitution are pure bashisms and may not work under other shells.



                  On my Debian GNU/Linux, there is a standard shell called dash, but I know many people who like to use ksh.



                  Finally, in very small situation, there is a special tool called busybox with his own shell interpreter (ash).



                  Requested string



                  The string sample in SO question is:



                  IN="bla@some.com;john@home.com"


                  As this could be useful with whitespaces and as whitespaces could modify the result of the routine, I prefer to use this sample string:



                   IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"


                  Split string based on delimiter in bash (version >=4.2)



                  Under pure bash, we may use arrays and IFS:



                  var="bla@some.com;john@home.com;Full Name <fulnam@other.org>"




                  oIFS="$IFS"
                  IFS=";"
                  declare -a fields=($var)
                  IFS="$oIFS"
                  unset oIFS




                  IFS=; read -a fields <<<"$IN"


                  Using this syntax under recent bash don't change $IFS for current session, but only for the current command:



                  set | grep ^IFS=
                  IFS=$' tn'


                  Now the string var is split and stored into an array (named fields):



                  set | grep ^fields=\|^var=
                  fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")
                  var='bla@some.com;john@home.com;Full Name <fulnam@other.org>'


                  We could request for variable content with declare -p:



                  declare -p IN fields
                  declare -- IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
                  declare -a fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")


                  read is the quickiest way to do the split, because there is no forks and no external resources called.



                  From there, you could use the syntax you already know for processing each field:



                  for x in "${fields[@]}";do
                  echo "> [$x]"
                  done
                  > [bla@some.com]
                  > [john@home.com]
                  > [Full Name <fulnam@other.org>]


                  or drop each field after processing (I like this shifting approach):



                  while [ "$fields" ] ;do
                  echo "> [$fields]"
                  fields=("${fields[@]:1}")
                  done
                  > [bla@some.com]
                  > [john@home.com]
                  > [Full Name <fulnam@other.org>]


                  or even for simple printout (shorter syntax):



                  printf "> [%s]n" "${fields[@]}"
                  > [bla@some.com]
                  > [john@home.com]
                  > [Full Name <fulnam@other.org>]


                  Update: recent bash >= 4.4



                  You could play with mapfile:



                  mapfile -td ; fields < <(printf "%s" "$IN")


                  This syntax preserve special chars, newlines and empty fields!



                  If you don't care about empty fields, you could:



                  mapfile -td ; fields <<<"$IN"
                  fields=("${fields[@]%$'n'}") # drop 'n' added by '<<<'


                  But you could use fields through function:



                  myPubliMail() {
                  printf "Seq: %6d: Sending mail to '%s'..." $1 "$2"
                  # mail -s "This is not a spam..." "$2" </path/to/body
                  printf "e[3D, done.n"
                  }

                  mapfile < <(printf "%s" "$IN") -td ; -c 1 -C myPubliMail


                  (Nota: at end of format string are useless while you don't care about empty fields at end of string)



                  mapfile < <(echo -n "$IN") -td ; -c 1 -C myPubliMail


                  Will render something like:



                  Seq:      0: Sending mail to 'bla@some.com', done.
                  Seq: 1: Sending mail to 'john@home.com', done.
                  Seq: 2: Sending mail to 'Full Name <fulnam@other.org>', done.


                  Or Drop newline added by <<< bash syntax in function:



                  myPubliMail() {
                  local seq=$1 dest="${2%$'n'}"
                  printf "Seq: %6d: Sending mail to '%s'..." $seq "$dest"
                  # mail -s "This is not a spam..." "$dest" </path/to/body
                  printf "e[3D, done.n"
                  }

                  mapfile <<<"$IN" -td ; -c 1 -C myPubliMail


                  Will render same output:



                  Seq:      0: Sending mail to 'bla@some.com', done.
                  Seq: 1: Sending mail to 'john@home.com', done.
                  Seq: 2: Sending mail to 'Full Name <fulnam@other.org>', done.


                  Split string based on delimiter in shell



                  But if you would write something usable under many shells, you have to not use bashisms.



                  There is a syntax, used in many shells, for splitting a string across first or last occurrence of a substring:



                  ${var#*SubStr}  # will drop begin of string up to first occur of `SubStr`
                  ${var##*SubStr} # will drop begin of string up to last occur of `SubStr`
                  ${var%SubStr*} # will drop part of string from last occur of `SubStr` to the end
                  ${var%%SubStr*} # will drop part of string from first occur of `SubStr` to the end


                  (The missing of this is the main reason of my answer publication ;)



                  As pointed out by Score_Under:




                  # and % delete the shortest possible matching string, and



                  ## and %% delete the longest possible.



                  where # and ## mean from left (begin) of string, and



                  % and %% meand from right (end) of string.




                  This little sample script work well under bash, dash, ksh, busybox and was tested under Mac-OS's bash too:



                  var="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
                  while [ "$var" ] ;do
                  iter=${var%%;*}
                  echo "> [$iter]"
                  [ "$var" = "$iter" ] &&
                  var='' ||
                  var="${var#*;}"
                  done
                  > [bla@some.com]
                  > [john@home.com]
                  > [Full Name <fulnam@other.org>]


                  Have fun!






                  share|improve this answer














                  Compatible answer



                  To this SO question, there is already a lot of different way to do this in bash.
                  But bash has many special features, so called bashism that work well, but that won't work in any other shell.



                  In particular, arrays, associative array, and pattern substitution are pure bashisms and may not work under other shells.



                  On my Debian GNU/Linux, there is a standard shell called dash, but I know many people who like to use ksh.



                  Finally, in very small situation, there is a special tool called busybox with his own shell interpreter (ash).



                  Requested string



                  The string sample in SO question is:



                  IN="bla@some.com;john@home.com"


                  As this could be useful with whitespaces and as whitespaces could modify the result of the routine, I prefer to use this sample string:



                   IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"


                  Split string based on delimiter in bash (version >=4.2)



                  Under pure bash, we may use arrays and IFS:



                  var="bla@some.com;john@home.com;Full Name <fulnam@other.org>"




                  oIFS="$IFS"
                  IFS=";"
                  declare -a fields=($var)
                  IFS="$oIFS"
                  unset oIFS




                  IFS=; read -a fields <<<"$IN"


                  Using this syntax under recent bash don't change $IFS for current session, but only for the current command:



                  set | grep ^IFS=
                  IFS=$' tn'


                  Now the string var is split and stored into an array (named fields):



                  set | grep ^fields=\|^var=
                  fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")
                  var='bla@some.com;john@home.com;Full Name <fulnam@other.org>'


                  We could request for variable content with declare -p:



                  declare -p IN fields
                  declare -- IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
                  declare -a fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")


                  read is the quickiest way to do the split, because there is no forks and no external resources called.



                  From there, you could use the syntax you already know for processing each field:



                  for x in "${fields[@]}";do
                  echo "> [$x]"
                  done
                  > [bla@some.com]
                  > [john@home.com]
                  > [Full Name <fulnam@other.org>]


                  or drop each field after processing (I like this shifting approach):



                  while [ "$fields" ] ;do
                  echo "> [$fields]"
                  fields=("${fields[@]:1}")
                  done
                  > [bla@some.com]
                  > [john@home.com]
                  > [Full Name <fulnam@other.org>]


                  or even for simple printout (shorter syntax):



                  printf "> [%s]n" "${fields[@]}"
                  > [bla@some.com]
                  > [john@home.com]
                  > [Full Name <fulnam@other.org>]


                  Update: recent bash >= 4.4



                  You could play with mapfile:



                  mapfile -td ; fields < <(printf "%s" "$IN")


                  This syntax preserve special chars, newlines and empty fields!



                  If you don't care about empty fields, you could:



                  mapfile -td ; fields <<<"$IN"
                  fields=("${fields[@]%$'n'}") # drop 'n' added by '<<<'


                  But you could use fields through function:



                  myPubliMail() {
                  printf "Seq: %6d: Sending mail to '%s'..." $1 "$2"
                  # mail -s "This is not a spam..." "$2" </path/to/body
                  printf "e[3D, done.n"
                  }

                  mapfile < <(printf "%s" "$IN") -td ; -c 1 -C myPubliMail


                  (Nota: at end of format string are useless while you don't care about empty fields at end of string)



                  mapfile < <(echo -n "$IN") -td ; -c 1 -C myPubliMail


                  Will render something like:



                  Seq:      0: Sending mail to 'bla@some.com', done.
                  Seq: 1: Sending mail to 'john@home.com', done.
                  Seq: 2: Sending mail to 'Full Name <fulnam@other.org>', done.


                  Or Drop newline added by <<< bash syntax in function:



                  myPubliMail() {
                  local seq=$1 dest="${2%$'n'}"
                  printf "Seq: %6d: Sending mail to '%s'..." $seq "$dest"
                  # mail -s "This is not a spam..." "$dest" </path/to/body
                  printf "e[3D, done.n"
                  }

                  mapfile <<<"$IN" -td ; -c 1 -C myPubliMail


                  Will render same output:



                  Seq:      0: Sending mail to 'bla@some.com', done.
                  Seq: 1: Sending mail to 'john@home.com', done.
                  Seq: 2: Sending mail to 'Full Name <fulnam@other.org>', done.


                  Split string based on delimiter in shell



                  But if you would write something usable under many shells, you have to not use bashisms.



                  There is a syntax, used in many shells, for splitting a string across first or last occurrence of a substring:



                  ${var#*SubStr}  # will drop begin of string up to first occur of `SubStr`
                  ${var##*SubStr} # will drop begin of string up to last occur of `SubStr`
                  ${var%SubStr*} # will drop part of string from last occur of `SubStr` to the end
                  ${var%%SubStr*} # will drop part of string from first occur of `SubStr` to the end


                  (The missing of this is the main reason of my answer publication ;)



                  As pointed out by Score_Under:




                  # and % delete the shortest possible matching string, and



                  ## and %% delete the longest possible.



                  where # and ## mean from left (begin) of string, and



                  % and %% meand from right (end) of string.




                  This little sample script work well under bash, dash, ksh, busybox and was tested under Mac-OS's bash too:



                  var="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
                  while [ "$var" ] ;do
                  iter=${var%%;*}
                  echo "> [$iter]"
                  [ "$var" = "$iter" ] &&
                  var='' ||
                  var="${var#*;}"
                  done
                  > [bla@some.com]
                  > [john@home.com]
                  > [Full Name <fulnam@other.org>]


                  Have fun!







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 9 at 13:06

























                  answered Apr 13 '13 at 14:20









                  F. Hauri

                  34.7k86488




                  34.7k86488








                  • 11




                    The #, ##, %, and %% substitutions have what is IMO an easier explanation to remember (for how much they delete): # and % delete the shortest possible matching string, and ## and %% delete the longest possible.
                    – Score_Under
                    Apr 28 '15 at 16:58








                  • 1




                    The IFS=; read -a fields <<<"$var" fails on newlines and add a trailing newline. The other solution removes a trailing empty field.
                    – sorontar
                    Oct 26 '16 at 4:36










                  • The shell delimiter is the most elegant answer, period.
                    – Eric Chen
                    Aug 30 '17 at 17:50












                  • Could the last alternative be used with a list of field separators set somewhere else? For instance, I mean to use this as a shell script, and pass a list of field separators as a positional parameter.
                    – sancho.s
                    Oct 4 at 3:42










                  • Yes, in a loop: for sep in "#" "ł" "@" ; do ... var="${var#*$sep}" ...
                    – F. Hauri
                    Oct 4 at 7:47
















                  • 11




                    The #, ##, %, and %% substitutions have what is IMO an easier explanation to remember (for how much they delete): # and % delete the shortest possible matching string, and ## and %% delete the longest possible.
                    – Score_Under
                    Apr 28 '15 at 16:58








                  • 1




                    The IFS=; read -a fields <<<"$var" fails on newlines and add a trailing newline. The other solution removes a trailing empty field.
                    – sorontar
                    Oct 26 '16 at 4:36










                  • The shell delimiter is the most elegant answer, period.
                    – Eric Chen
                    Aug 30 '17 at 17:50












                  • Could the last alternative be used with a list of field separators set somewhere else? For instance, I mean to use this as a shell script, and pass a list of field separators as a positional parameter.
                    – sancho.s
                    Oct 4 at 3:42










                  • Yes, in a loop: for sep in "#" "ł" "@" ; do ... var="${var#*$sep}" ...
                    – F. Hauri
                    Oct 4 at 7:47










                  11




                  11




                  The #, ##, %, and %% substitutions have what is IMO an easier explanation to remember (for how much they delete): # and % delete the shortest possible matching string, and ## and %% delete the longest possible.
                  – Score_Under
                  Apr 28 '15 at 16:58






                  The #, ##, %, and %% substitutions have what is IMO an easier explanation to remember (for how much they delete): # and % delete the shortest possible matching string, and ## and %% delete the longest possible.
                  – Score_Under
                  Apr 28 '15 at 16:58






                  1




                  1




                  The IFS=; read -a fields <<<"$var" fails on newlines and add a trailing newline. The other solution removes a trailing empty field.
                  – sorontar
                  Oct 26 '16 at 4:36




                  The IFS=; read -a fields <<<"$var" fails on newlines and add a trailing newline. The other solution removes a trailing empty field.
                  – sorontar
                  Oct 26 '16 at 4:36












                  The shell delimiter is the most elegant answer, period.
                  – Eric Chen
                  Aug 30 '17 at 17:50






                  The shell delimiter is the most elegant answer, period.
                  – Eric Chen
                  Aug 30 '17 at 17:50














                  Could the last alternative be used with a list of field separators set somewhere else? For instance, I mean to use this as a shell script, and pass a list of field separators as a positional parameter.
                  – sancho.s
                  Oct 4 at 3:42




                  Could the last alternative be used with a list of field separators set somewhere else? For instance, I mean to use this as a shell script, and pass a list of field separators as a positional parameter.
                  – sancho.s
                  Oct 4 at 3:42












                  Yes, in a loop: for sep in "#" "ł" "@" ; do ... var="${var#*$sep}" ...
                  – F. Hauri
                  Oct 4 at 7:47






                  Yes, in a loop: for sep in "#" "ł" "@" ; do ... var="${var#*$sep}" ...
                  – F. Hauri
                  Oct 4 at 7:47












                  up vote
                  96
                  down vote













                  I've seen a couple of answers referencing the cut command, but they've all been deleted. It's a little odd that nobody has elaborated on that, because I think it's one of the more useful commands for doing this type of thing, especially for parsing delimited log files.



                  In the case of splitting this specific example into a bash script array, tr is probably more efficient, but cut can be used, and is more effective if you want to pull specific fields from the middle.



                  Example:



                  $ echo "bla@some.com;john@home.com" | cut -d ";" -f 1
                  bla@some.com
                  $ echo "bla@some.com;john@home.com" | cut -d ";" -f 2
                  john@home.com


                  You can obviously put that into a loop, and iterate the -f parameter to pull each field independently.



                  This gets more useful when you have a delimited log file with rows like this:



                  2015-04-27|12345|some action|an attribute|meta data


                  cut is very handy to be able to cat this file and select a particular field for further processing.






                  share|improve this answer



















                  • 2




                    Kudos for using cut, it's the right tool for the job! Much cleared than any of those shell hacks.
                    – MisterMiyagi
                    Nov 2 '16 at 8:42






                  • 2




                    This approach will only work if you know the number of elements in advance; you'd need to program some more logic around it. It also runs an external tool for every element.
                    – uli42
                    Sep 14 '17 at 8:30










                  • Excatly waht i was looking for trying to avoid empty string in a csv. Now i can point the exact 'column' value as well. Work with IFS already used in a loop. Better than expected for my situation.
                    – Louis Loudog Trottier
                    May 10 at 4:20















                  up vote
                  96
                  down vote













                  I've seen a couple of answers referencing the cut command, but they've all been deleted. It's a little odd that nobody has elaborated on that, because I think it's one of the more useful commands for doing this type of thing, especially for parsing delimited log files.



                  In the case of splitting this specific example into a bash script array, tr is probably more efficient, but cut can be used, and is more effective if you want to pull specific fields from the middle.



                  Example:



                  $ echo "bla@some.com;john@home.com" | cut -d ";" -f 1
                  bla@some.com
                  $ echo "bla@some.com;john@home.com" | cut -d ";" -f 2
                  john@home.com


                  You can obviously put that into a loop, and iterate the -f parameter to pull each field independently.



                  This gets more useful when you have a delimited log file with rows like this:



                  2015-04-27|12345|some action|an attribute|meta data


                  cut is very handy to be able to cat this file and select a particular field for further processing.






                  share|improve this answer



















                  • 2




                    Kudos for using cut, it's the right tool for the job! Much cleared than any of those shell hacks.
                    – MisterMiyagi
                    Nov 2 '16 at 8:42






                  • 2




                    This approach will only work if you know the number of elements in advance; you'd need to program some more logic around it. It also runs an external tool for every element.
                    – uli42
                    Sep 14 '17 at 8:30










                  • Excatly waht i was looking for trying to avoid empty string in a csv. Now i can point the exact 'column' value as well. Work with IFS already used in a loop. Better than expected for my situation.
                    – Louis Loudog Trottier
                    May 10 at 4:20













                  up vote
                  96
                  down vote










                  up vote
                  96
                  down vote









                  I've seen a couple of answers referencing the cut command, but they've all been deleted. It's a little odd that nobody has elaborated on that, because I think it's one of the more useful commands for doing this type of thing, especially for parsing delimited log files.



                  In the case of splitting this specific example into a bash script array, tr is probably more efficient, but cut can be used, and is more effective if you want to pull specific fields from the middle.



                  Example:



                  $ echo "bla@some.com;john@home.com" | cut -d ";" -f 1
                  bla@some.com
                  $ echo "bla@some.com;john@home.com" | cut -d ";" -f 2
                  john@home.com


                  You can obviously put that into a loop, and iterate the -f parameter to pull each field independently.



                  This gets more useful when you have a delimited log file with rows like this:



                  2015-04-27|12345|some action|an attribute|meta data


                  cut is very handy to be able to cat this file and select a particular field for further processing.






                  share|improve this answer














                  I've seen a couple of answers referencing the cut command, but they've all been deleted. It's a little odd that nobody has elaborated on that, because I think it's one of the more useful commands for doing this type of thing, especially for parsing delimited log files.



                  In the case of splitting this specific example into a bash script array, tr is probably more efficient, but cut can be used, and is more effective if you want to pull specific fields from the middle.



                  Example:



                  $ echo "bla@some.com;john@home.com" | cut -d ";" -f 1
                  bla@some.com
                  $ echo "bla@some.com;john@home.com" | cut -d ";" -f 2
                  john@home.com


                  You can obviously put that into a loop, and iterate the -f parameter to pull each field independently.



                  This gets more useful when you have a delimited log file with rows like this:



                  2015-04-27|12345|some action|an attribute|meta data


                  cut is very handy to be able to cat this file and select a particular field for further processing.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Apr 28 '15 at 22:17

























                  answered Apr 27 '15 at 18:20









                  DougW

                  16.7k1568102




                  16.7k1568102








                  • 2




                    Kudos for using cut, it's the right tool for the job! Much cleared than any of those shell hacks.
                    – MisterMiyagi
                    Nov 2 '16 at 8:42






                  • 2




                    This approach will only work if you know the number of elements in advance; you'd need to program some more logic around it. It also runs an external tool for every element.
                    – uli42
                    Sep 14 '17 at 8:30










                  • Excatly waht i was looking for trying to avoid empty string in a csv. Now i can point the exact 'column' value as well. Work with IFS already used in a loop. Better than expected for my situation.
                    – Louis Loudog Trottier
                    May 10 at 4:20














                  • 2




                    Kudos for using cut, it's the right tool for the job! Much cleared than any of those shell hacks.
                    – MisterMiyagi
                    Nov 2 '16 at 8:42






                  • 2




                    This approach will only work if you know the number of elements in advance; you'd need to program some more logic around it. It also runs an external tool for every element.
                    – uli42
                    Sep 14 '17 at 8:30










                  • Excatly waht i was looking for trying to avoid empty string in a csv. Now i can point the exact 'column' value as well. Work with IFS already used in a loop. Better than expected for my situation.
                    – Louis Loudog Trottier
                    May 10 at 4:20








                  2




                  2




                  Kudos for using cut, it's the right tool for the job! Much cleared than any of those shell hacks.
                  – MisterMiyagi
                  Nov 2 '16 at 8:42




                  Kudos for using cut, it's the right tool for the job! Much cleared than any of those shell hacks.
                  – MisterMiyagi
                  Nov 2 '16 at 8:42




                  2




                  2




                  This approach will only work if you know the number of elements in advance; you'd need to program some more logic around it. It also runs an external tool for every element.
                  – uli42
                  Sep 14 '17 at 8:30




                  This approach will only work if you know the number of elements in advance; you'd need to program some more logic around it. It also runs an external tool for every element.
                  – uli42
                  Sep 14 '17 at 8:30












                  Excatly waht i was looking for trying to avoid empty string in a csv. Now i can point the exact 'column' value as well. Work with IFS already used in a loop. Better than expected for my situation.
                  – Louis Loudog Trottier
                  May 10 at 4:20




                  Excatly waht i was looking for trying to avoid empty string in a csv. Now i can point the exact 'column' value as well. Work with IFS already used in a loop. Better than expected for my situation.
                  – Louis Loudog Trottier
                  May 10 at 4:20










                  up vote
                  81
                  down vote













                  How about this approach:



                  IN="bla@some.com;john@home.com" 
                  set -- "$IN"
                  IFS=";"; declare -a Array=($*)
                  echo "${Array[@]}"
                  echo "${Array[0]}"
                  echo "${Array[1]}"


                  Source






                  share|improve this answer



















                  • 6




                    +1 ... but I wouldn't name the variable "Array" ... pet peev I guess. Good solution.
                    – Yzmir Ramirez
                    Sep 5 '11 at 1:06






                  • 14




                    +1 ... but the "set" and declare -a are unnecessary. You could as well have used just IFS";" && Array=($IN)
                    – ata
                    Nov 3 '11 at 22:33












                  • +1 Only a side note: shouldn't it be recommendable to keep the old IFS and then restore it? (as shown by stefanB in his edit3) people landing here (sometimes just copying and pasting a solution) might not think about this
                    – Luca Borrione
                    Sep 3 '12 at 9:26






                  • 6




                    -1: First, @ata is right that most of the commands in this do nothing. Second, it uses word-splitting to form the array, and doesn't do anything to inhibit glob-expansion when doing so (so if you have glob characters in any of the array elements, those elements are replaced with matching filenames).
                    – Charles Duffy
                    Jul 6 '13 at 14:44






                  • 1




                    Suggest to use $'...': IN=$'bla@some.com;john@home.com;bet <d@ns* kl.com>'. Then echo "${Array[2]}" will print a string with newline. set -- "$IN" is also neccessary in this case. Yes, to prevent glob expansion, the solution should include set -f.
                    – John_West
                    Jan 8 '16 at 12:29















                  up vote
                  81
                  down vote













                  How about this approach:



                  IN="bla@some.com;john@home.com" 
                  set -- "$IN"
                  IFS=";"; declare -a Array=($*)
                  echo "${Array[@]}"
                  echo "${Array[0]}"
                  echo "${Array[1]}"


                  Source






                  share|improve this answer



















                  • 6




                    +1 ... but I wouldn't name the variable "Array" ... pet peev I guess. Good solution.
                    – Yzmir Ramirez
                    Sep 5 '11 at 1:06






                  • 14




                    +1 ... but the "set" and declare -a are unnecessary. You could as well have used just IFS";" && Array=($IN)
                    – ata
                    Nov 3 '11 at 22:33












                  • +1 Only a side note: shouldn't it be recommendable to keep the old IFS and then restore it? (as shown by stefanB in his edit3) people landing here (sometimes just copying and pasting a solution) might not think about this
                    – Luca Borrione
                    Sep 3 '12 at 9:26






                  • 6




                    -1: First, @ata is right that most of the commands in this do nothing. Second, it uses word-splitting to form the array, and doesn't do anything to inhibit glob-expansion when doing so (so if you have glob characters in any of the array elements, those elements are replaced with matching filenames).
                    – Charles Duffy
                    Jul 6 '13 at 14:44






                  • 1




                    Suggest to use $'...': IN=$'bla@some.com;john@home.com;bet <d@ns* kl.com>'. Then echo "${Array[2]}" will print a string with newline. set -- "$IN" is also neccessary in this case. Yes, to prevent glob expansion, the solution should include set -f.
                    – John_West
                    Jan 8 '16 at 12:29













                  up vote
                  81
                  down vote










                  up vote
                  81
                  down vote









                  How about this approach:



                  IN="bla@some.com;john@home.com" 
                  set -- "$IN"
                  IFS=";"; declare -a Array=($*)
                  echo "${Array[@]}"
                  echo "${Array[0]}"
                  echo "${Array[1]}"


                  Source






                  share|improve this answer














                  How about this approach:



                  IN="bla@some.com;john@home.com" 
                  set -- "$IN"
                  IFS=";"; declare -a Array=($*)
                  echo "${Array[@]}"
                  echo "${Array[0]}"
                  echo "${Array[1]}"


                  Source







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Jul 20 '11 at 16:21









                  BLeB

                  1,4871524




                  1,4871524










                  answered May 28 '09 at 10:31







                  errator















                  • 6




                    +1 ... but I wouldn't name the variable "Array" ... pet peev I guess. Good solution.
                    – Yzmir Ramirez
                    Sep 5 '11 at 1:06






                  • 14




                    +1 ... but the "set" and declare -a are unnecessary. You could as well have used just IFS";" && Array=($IN)
                    – ata
                    Nov 3 '11 at 22:33












                  • +1 Only a side note: shouldn't it be recommendable to keep the old IFS and then restore it? (as shown by stefanB in his edit3) people landing here (sometimes just copying and pasting a solution) might not think about this
                    – Luca Borrione
                    Sep 3 '12 at 9:26






                  • 6




                    -1: First, @ata is right that most of the commands in this do nothing. Second, it uses word-splitting to form the array, and doesn't do anything to inhibit glob-expansion when doing so (so if you have glob characters in any of the array elements, those elements are replaced with matching filenames).
                    – Charles Duffy
                    Jul 6 '13 at 14:44






                  • 1




                    Suggest to use $'...': IN=$'bla@some.com;john@home.com;bet <d@ns* kl.com>'. Then echo "${Array[2]}" will print a string with newline. set -- "$IN" is also neccessary in this case. Yes, to prevent glob expansion, the solution should include set -f.
                    – John_West
                    Jan 8 '16 at 12:29














                  • 6




                    +1 ... but I wouldn't name the variable "Array" ... pet peev I guess. Good solution.
                    – Yzmir Ramirez
                    Sep 5 '11 at 1:06






                  • 14




                    +1 ... but the "set" and declare -a are unnecessary. You could as well have used just IFS";" && Array=($IN)
                    – ata
                    Nov 3 '11 at 22:33












                  • +1 Only a side note: shouldn't it be recommendable to keep the old IFS and then restore it? (as shown by stefanB in his edit3) people landing here (sometimes just copying and pasting a solution) might not think about this
                    – Luca Borrione
                    Sep 3 '12 at 9:26






                  • 6




                    -1: First, @ata is right that most of the commands in this do nothing. Second, it uses word-splitting to form the array, and doesn't do anything to inhibit glob-expansion when doing so (so if you have glob characters in any of the array elements, those elements are replaced with matching filenames).
                    – Charles Duffy
                    Jul 6 '13 at 14:44






                  • 1




                    Suggest to use $'...': IN=$'bla@some.com;john@home.com;bet <d@ns* kl.com>'. Then echo "${Array[2]}" will print a string with newline. set -- "$IN" is also neccessary in this case. Yes, to prevent glob expansion, the solution should include set -f.
                    – John_West
                    Jan 8 '16 at 12:29








                  6




                  6




                  +1 ... but I wouldn't name the variable "Array" ... pet peev I guess. Good solution.
                  – Yzmir Ramirez
                  Sep 5 '11 at 1:06




                  +1 ... but I wouldn't name the variable "Array" ... pet peev I guess. Good solution.
                  – Yzmir Ramirez
                  Sep 5 '11 at 1:06




                  14




                  14




                  +1 ... but the "set" and declare -a are unnecessary. You could as well have used just IFS";" && Array=($IN)
                  – ata
                  Nov 3 '11 at 22:33






                  +1 ... but the "set" and declare -a are unnecessary. You could as well have used just IFS";" && Array=($IN)
                  – ata
                  Nov 3 '11 at 22:33














                  +1 Only a side note: shouldn't it be recommendable to keep the old IFS and then restore it? (as shown by stefanB in his edit3) people landing here (sometimes just copying and pasting a solution) might not think about this
                  – Luca Borrione
                  Sep 3 '12 at 9:26




                  +1 Only a side note: shouldn't it be recommendable to keep the old IFS and then restore it? (as shown by stefanB in his edit3) people landing here (sometimes just copying and pasting a solution) might not think about this
                  – Luca Borrione
                  Sep 3 '12 at 9:26




                  6




                  6




                  -1: First, @ata is right that most of the commands in this do nothing. Second, it uses word-splitting to form the array, and doesn't do anything to inhibit glob-expansion when doing so (so if you have glob characters in any of the array elements, those elements are replaced with matching filenames).
                  – Charles Duffy
                  Jul 6 '13 at 14:44




                  -1: First, @ata is right that most of the commands in this do nothing. Second, it uses word-splitting to form the array, and doesn't do anything to inhibit glob-expansion when doing so (so if you have glob characters in any of the array elements, those elements are replaced with matching filenames).
                  – Charles Duffy
                  Jul 6 '13 at 14:44




                  1




                  1




                  Suggest to use $'...': IN=$'bla@some.com;john@home.com;bet <d@ns* kl.com>'. Then echo "${Array[2]}" will print a string with newline. set -- "$IN" is also neccessary in this case. Yes, to prevent glob expansion, the solution should include set -f.
                  – John_West
                  Jan 8 '16 at 12:29




                  Suggest to use $'...': IN=$'bla@some.com;john@home.com;bet <d@ns* kl.com>'. Then echo "${Array[2]}" will print a string with newline. set -- "$IN" is also neccessary in this case. Yes, to prevent glob expansion, the solution should include set -f.
                  – John_West
                  Jan 8 '16 at 12:29










                  up vote
                  79
                  down vote













                  This worked for me:



                  string="1;2"
                  echo $string | cut -d';' -f1 # output is 1
                  echo $string | cut -d';' -f2 # output is 2





                  share|improve this answer























                  • this is sort and sweet :)
                    – Pardeep Sharma
                    Oct 10 '17 at 7:29










                  • Thanks...Helped a lot
                    – space earth
                    Oct 17 '17 at 7:23










                  • cut works only with a single char as delimiter.
                    – mojjj
                    Jan 8 at 8:57















                  up vote
                  79
                  down vote













                  This worked for me:



                  string="1;2"
                  echo $string | cut -d';' -f1 # output is 1
                  echo $string | cut -d';' -f2 # output is 2





                  share|improve this answer























                  • this is sort and sweet :)
                    – Pardeep Sharma
                    Oct 10 '17 at 7:29










                  • Thanks...Helped a lot
                    – space earth
                    Oct 17 '17 at 7:23










                  • cut works only with a single char as delimiter.
                    – mojjj
                    Jan 8 at 8:57













                  up vote
                  79
                  down vote










                  up vote
                  79
                  down vote









                  This worked for me:



                  string="1;2"
                  echo $string | cut -d';' -f1 # output is 1
                  echo $string | cut -d';' -f2 # output is 2





                  share|improve this answer














                  This worked for me:



                  string="1;2"
                  echo $string | cut -d';' -f1 # output is 1
                  echo $string | cut -d';' -f2 # output is 2






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Jan 24 '17 at 2:33









                  lfender6445

                  15k67062




                  15k67062










                  answered Aug 11 '16 at 20:45









                  Steven Lizarazo

                  3,1182121




                  3,1182121












                  • this is sort and sweet :)
                    – Pardeep Sharma
                    Oct 10 '17 at 7:29










                  • Thanks...Helped a lot
                    – space earth
                    Oct 17 '17 at 7:23










                  • cut works only with a single char as delimiter.
                    – mojjj
                    Jan 8 at 8:57


















                  • this is sort and sweet :)
                    – Pardeep Sharma
                    Oct 10 '17 at 7:29










                  • Thanks...Helped a lot
                    – space earth
                    Oct 17 '17 at 7:23










                  • cut works only with a single char as delimiter.
                    – mojjj
                    Jan 8 at 8:57
















                  this is sort and sweet :)
                  – Pardeep Sharma
                  Oct 10 '17 at 7:29




                  this is sort and sweet :)
                  – Pardeep Sharma
                  Oct 10 '17 at 7:29












                  Thanks...Helped a lot
                  – space earth
                  Oct 17 '17 at 7:23




                  Thanks...Helped a lot
                  – space earth
                  Oct 17 '17 at 7:23












                  cut works only with a single char as delimiter.
                  – mojjj
                  Jan 8 at 8:57




                  cut works only with a single char as delimiter.
                  – mojjj
                  Jan 8 at 8:57










                  up vote
                  59
                  down vote













                  echo "bla@some.com;john@home.com" | sed -e 's/;/n/g'
                  bla@some.com
                  john@home.com





                  share|improve this answer

















                  • 3




                    -1 what if the string contains spaces? for example IN="this is first line; this is second line" arrIN=( $( echo "$IN" | sed -e 's/;/n/g' ) ) will produce an array of 8 elements in this case (an element for each word space separated), rather than 2 (an element for each line semi colon separated)
                    – Luca Borrione
                    Sep 3 '12 at 10:08






                  • 2




                    @Luca No the sed script creates exactly two lines. What creates the multiple entries for you is when you put it into a bash array (which splits on white space by default)
                    – lothar
                    Sep 3 '12 at 17:33










                  • That's exactly the point: the OP needs to store entries into an array to loop over it, as you can see in his edits. I think your (good) answer missed to mention to use arrIN=( $( echo "$IN" | sed -e 's/;/n/g' ) ) to achieve that, and to advice to change IFS to IFS=$'n' for those who land here in the future and needs to split a string containing spaces. (and to restore it back afterwards). :)
                    – Luca Borrione
                    Sep 4 '12 at 7:09






                  • 1




                    @Luca Good point. However the array assignment was not in the initial question when I wrote up that answer.
                    – lothar
                    Sep 4 '12 at 16:55















                  up vote
                  59
                  down vote













                  echo "bla@some.com;john@home.com" | sed -e 's/;/n/g'
                  bla@some.com
                  john@home.com





                  share|improve this answer

















                  • 3




                    -1 what if the string contains spaces? for example IN="this is first line; this is second line" arrIN=( $( echo "$IN" | sed -e 's/;/n/g' ) ) will produce an array of 8 elements in this case (an element for each word space separated), rather than 2 (an element for each line semi colon separated)
                    – Luca Borrione
                    Sep 3 '12 at 10:08






                  • 2




                    @Luca No the sed script creates exactly two lines. What creates the multiple entries for you is when you put it into a bash array (which splits on white space by default)
                    – lothar
                    Sep 3 '12 at 17:33










                  • That's exactly the point: the OP needs to store entries into an array to loop over it, as you can see in his edits. I think your (good) answer missed to mention to use arrIN=( $( echo "$IN" | sed -e 's/;/n/g' ) ) to achieve that, and to advice to change IFS to IFS=$'n' for those who land here in the future and needs to split a string containing spaces. (and to restore it back afterwards). :)
                    – Luca Borrione
                    Sep 4 '12 at 7:09






                  • 1




                    @Luca Good point. However the array assignment was not in the initial question when I wrote up that answer.
                    – lothar
                    Sep 4 '12 at 16:55













                  up vote
                  59
                  down vote










                  up vote
                  59
                  down vote









                  echo "bla@some.com;john@home.com" | sed -e 's/;/n/g'
                  bla@some.com
                  john@home.com





                  share|improve this answer












                  echo "bla@some.com;john@home.com" | sed -e 's/;/n/g'
                  bla@some.com
                  john@home.com






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered May 28 '09 at 2:12









                  lothar

                  16.7k43857




                  16.7k43857








                  • 3




                    -1 what if the string contains spaces? for example IN="this is first line; this is second line" arrIN=( $( echo "$IN" | sed -e 's/;/n/g' ) ) will produce an array of 8 elements in this case (an element for each word space separated), rather than 2 (an element for each line semi colon separated)
                    – Luca Borrione
                    Sep 3 '12 at 10:08






                  • 2




                    @Luca No the sed script creates exactly two lines. What creates the multiple entries for you is when you put it into a bash array (which splits on white space by default)
                    – lothar
                    Sep 3 '12 at 17:33










                  • That's exactly the point: the OP needs to store entries into an array to loop over it, as you can see in his edits. I think your (good) answer missed to mention to use arrIN=( $( echo "$IN" | sed -e 's/;/n/g' ) ) to achieve that, and to advice to change IFS to IFS=$'n' for those who land here in the future and needs to split a string containing spaces. (and to restore it back afterwards). :)
                    – Luca Borrione
                    Sep 4 '12 at 7:09






                  • 1




                    @Luca Good point. However the array assignment was not in the initial question when I wrote up that answer.
                    – lothar
                    Sep 4 '12 at 16:55














                  • 3




                    -1 what if the string contains spaces? for example IN="this is first line; this is second line" arrIN=( $( echo "$IN" | sed -e 's/;/n/g' ) ) will produce an array of 8 elements in this case (an element for each word space separated), rather than 2 (an element for each line semi colon separated)
                    – Luca Borrione
                    Sep 3 '12 at 10:08






                  • 2




                    @Luca No the sed script creates exactly two lines. What creates the multiple entries for you is when you put it into a bash array (which splits on white space by default)
                    – lothar
                    Sep 3 '12 at 17:33










                  • That's exactly the point: the OP needs to store entries into an array to loop over it, as you can see in his edits. I think your (good) answer missed to mention to use arrIN=( $( echo "$IN" | sed -e 's/;/n/g' ) ) to achieve that, and to advice to change IFS to IFS=$'n' for those who land here in the future and needs to split a string containing spaces. (and to restore it back afterwards). :)
                    – Luca Borrione
                    Sep 4 '12 at 7:09






                  • 1




                    @Luca Good point. However the array assignment was not in the initial question when I wrote up that answer.
                    – lothar
                    Sep 4 '12 at 16:55








                  3




                  3




                  -1 what if the string contains spaces? for example IN="this is first line; this is second line" arrIN=( $( echo "$IN" | sed -e 's/;/n/g' ) ) will produce an array of 8 elements in this case (an element for each word space separated), rather than 2 (an element for each line semi colon separated)
                  – Luca Borrione
                  Sep 3 '12 at 10:08




                  -1 what if the string contains spaces? for example IN="this is first line; this is second line" arrIN=( $( echo "$IN" | sed -e 's/;/n/g' ) ) will produce an array of 8 elements in this case (an element for each word space separated), rather than 2 (an element for each line semi colon separated)
                  – Luca Borrione
                  Sep 3 '12 at 10:08




                  2




                  2




                  @Luca No the sed script creates exactly two lines. What creates the multiple entries for you is when you put it into a bash array (which splits on white space by default)
                  – lothar
                  Sep 3 '12 at 17:33




                  @Luca No the sed script creates exactly two lines. What creates the multiple entries for you is when you put it into a bash array (which splits on white space by default)
                  – lothar
                  Sep 3 '12 at 17:33












                  That's exactly the point: the OP needs to store entries into an array to loop over it, as you can see in his edits. I think your (good) answer missed to mention to use arrIN=( $( echo "$IN" | sed -e 's/;/n/g' ) ) to achieve that, and to advice to change IFS to IFS=$'n' for those who land here in the future and needs to split a string containing spaces. (and to restore it back afterwards). :)
                  – Luca Borrione
                  Sep 4 '12 at 7:09




                  That's exactly the point: the OP needs to store entries into an array to loop over it, as you can see in his edits. I think your (good) answer missed to mention to use arrIN=( $( echo "$IN" | sed -e 's/;/n/g' ) ) to achieve that, and to advice to change IFS to IFS=$'n' for those who land here in the future and needs to split a string containing spaces. (and to restore it back afterwards). :)
                  – Luca Borrione
                  Sep 4 '12 at 7:09




                  1




                  1




                  @Luca Good point. However the array assignment was not in the initial question when I wrote up that answer.
                  – lothar
                  Sep 4 '12 at 16:55




                  @Luca Good point. However the array assignment was not in the initial question when I wrote up that answer.
                  – lothar
                  Sep 4 '12 at 16:55










                  up vote
                  59
                  down vote













                  This also works:



                  IN="bla@some.com;john@home.com"
                  echo ADD1=`echo $IN | cut -d ; -f 1`
                  echo ADD2=`echo $IN | cut -d ; -f 2`


                  Be careful, this solution is not always correct. In case you pass "bla@some.com" only, it will assign it to both ADD1 and ADD2.






                  share|improve this answer



















                  • 1




                    You can use -s to avoid the mentioned problem: superuser.com/questions/896800/… "-f, --fields=LIST select only these fields; also print any line that contains no delimiter character, unless the -s option is specified"
                    – fersarr
                    Mar 3 '16 at 17:17















                  up vote
                  59
                  down vote













                  This also works:



                  IN="bla@some.com;john@home.com"
                  echo ADD1=`echo $IN | cut -d ; -f 1`
                  echo ADD2=`echo $IN | cut -d ; -f 2`


                  Be careful, this solution is not always correct. In case you pass "bla@some.com" only, it will assign it to both ADD1 and ADD2.






                  share|improve this answer



















                  • 1




                    You can use -s to avoid the mentioned problem: superuser.com/questions/896800/… "-f, --fields=LIST select only these fields; also print any line that contains no delimiter character, unless the -s option is specified"
                    – fersarr
                    Mar 3 '16 at 17:17













                  up vote
                  59
                  down vote










                  up vote
                  59
                  down vote









                  This also works:



                  IN="bla@some.com;john@home.com"
                  echo ADD1=`echo $IN | cut -d ; -f 1`
                  echo ADD2=`echo $IN | cut -d ; -f 2`


                  Be careful, this solution is not always correct. In case you pass "bla@some.com" only, it will assign it to both ADD1 and ADD2.






                  share|improve this answer














                  This also works:



                  IN="bla@some.com;john@home.com"
                  echo ADD1=`echo $IN | cut -d ; -f 1`
                  echo ADD2=`echo $IN | cut -d ; -f 2`


                  Be careful, this solution is not always correct. In case you pass "bla@some.com" only, it will assign it to both ADD1 and ADD2.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Apr 17 '14 at 1:39









                  Boris S.

                  32




                  32










                  answered Sep 8 '12 at 5:01









                  Ashok

                  60153




                  60153








                  • 1




                    You can use -s to avoid the mentioned problem: superuser.com/questions/896800/… "-f, --fields=LIST select only these fields; also print any line that contains no delimiter character, unless the -s option is specified"
                    – fersarr
                    Mar 3 '16 at 17:17














                  • 1




                    You can use -s to avoid the mentioned problem: superuser.com/questions/896800/… "-f, --fields=LIST select only these fields; also print any line that contains no delimiter character, unless the -s option is specified"
                    – fersarr
                    Mar 3 '16 at 17:17








                  1




                  1




                  You can use -s to avoid the mentioned problem: superuser.com/questions/896800/… "-f, --fields=LIST select only these fields; also print any line that contains no delimiter character, unless the -s option is specified"
                  – fersarr
                  Mar 3 '16 at 17:17




                  You can use -s to avoid the mentioned problem: superuser.com/questions/896800/… "-f, --fields=LIST select only these fields; also print any line that contains no delimiter character, unless the -s option is specified"
                  – fersarr
                  Mar 3 '16 at 17:17










                  up vote
                  34
                  down vote













                  I think AWK is the best and efficient command to resolve your problem. AWK is included in Bash by default in almost every Linux distribution.



                  echo "bla@some.com;john@home.com" | awk -F';' '{print $1,$2}'


                  will give



                  bla@some.com john@home.com


                  Of course your can store each email address by redefining the awk print field.






                  share|improve this answer



















                  • 2




                    Or even simpler: echo "bla@some.com;john@home.com" | awk 'BEGIN{RS=";"} {print}'
                    – Jaro
                    Jan 7 '14 at 21:30












                  • @Jaro This worked perfectly for me when I had a string with commas and needed to reformat it into lines. Thanks.
                    – Aquarelle
                    May 6 '14 at 21:58










                  • It worked in this scenario -> "echo "$SPLIT_0" | awk -F' inode=' '{print $1}'"! I had problems when trying to use atrings (" inode=") instead of characters (";"). $ 1, $ 2, $ 3, $ 4 are set as positions in an array! If there is a way of setting an array... better! Thanks!
                    – Eduardo Lucio
                    Aug 5 '15 at 12:59










                  • @EduardoLucio, what I'm thinking about is maybe you can first replace your delimiter inode= into ; for example by sed -i 's/inode=/;/g' your_file_to_process, then define -F';' when apply awk, hope that can help you.
                    – Tony
                    Aug 6 '15 at 2:42

















                  up vote
                  34
                  down vote













                  I think AWK is the best and efficient command to resolve your problem. AWK is included in Bash by default in almost every Linux distribution.



                  echo "bla@some.com;john@home.com" | awk -F';' '{print $1,$2}'


                  will give



                  bla@some.com john@home.com


                  Of course your can store each email address by redefining the awk print field.






                  share|improve this answer



















                  • 2




                    Or even simpler: echo "bla@some.com;john@home.com" | awk 'BEGIN{RS=";"} {print}'
                    – Jaro
                    Jan 7 '14 at 21:30












                  • @Jaro This worked perfectly for me when I had a string with commas and needed to reformat it into lines. Thanks.
                    – Aquarelle
                    May 6 '14 at 21:58










                  • It worked in this scenario -> "echo "$SPLIT_0" | awk -F' inode=' '{print $1}'"! I had problems when trying to use atrings (" inode=") instead of characters (";"). $ 1, $ 2, $ 3, $ 4 are set as positions in an array! If there is a way of setting an array... better! Thanks!
                    – Eduardo Lucio
                    Aug 5 '15 at 12:59










                  • @EduardoLucio, what I'm thinking about is maybe you can first replace your delimiter inode= into ; for example by sed -i 's/inode=/;/g' your_file_to_process, then define -F';' when apply awk, hope that can help you.
                    – Tony
                    Aug 6 '15 at 2:42















                  up vote
                  34
                  down vote










                  up vote
                  34
                  down vote









                  I think AWK is the best and efficient command to resolve your problem. AWK is included in Bash by default in almost every Linux distribution.



                  echo "bla@some.com;john@home.com" | awk -F';' '{print $1,$2}'


                  will give



                  bla@some.com john@home.com


                  Of course your can store each email address by redefining the awk print field.






                  share|improve this answer














                  I think AWK is the best and efficient command to resolve your problem. AWK is included in Bash by default in almost every Linux distribution.



                  echo "bla@some.com;john@home.com" | awk -F';' '{print $1,$2}'


                  will give



                  bla@some.com john@home.com


                  Of course your can store each email address by redefining the awk print field.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Apr 19 '15 at 22:26









                  Peter Mortensen

                  13.3k1983111




                  13.3k1983111










                  answered Jan 14 '13 at 6:33









                  Tony

                  6271617




                  6271617








                  • 2




                    Or even simpler: echo "bla@some.com;john@home.com" | awk 'BEGIN{RS=";"} {print}'
                    – Jaro
                    Jan 7 '14 at 21:30












                  • @Jaro This worked perfectly for me when I had a string with commas and needed to reformat it into lines. Thanks.
                    – Aquarelle
                    May 6 '14 at 21:58










                  • It worked in this scenario -> "echo "$SPLIT_0" | awk -F' inode=' '{print $1}'"! I had problems when trying to use atrings (" inode=") instead of characters (";"). $ 1, $ 2, $ 3, $ 4 are set as positions in an array! If there is a way of setting an array... better! Thanks!
                    – Eduardo Lucio
                    Aug 5 '15 at 12:59










                  • @EduardoLucio, what I'm thinking about is maybe you can first replace your delimiter inode= into ; for example by sed -i 's/inode=/;/g' your_file_to_process, then define -F';' when apply awk, hope that can help you.
                    – Tony
                    Aug 6 '15 at 2:42
















                  • 2




                    Or even simpler: echo "bla@some.com;john@home.com" | awk 'BEGIN{RS=";"} {print}'
                    – Jaro
                    Jan 7 '14 at 21:30












                  • @Jaro This worked perfectly for me when I had a string with commas and needed to reformat it into lines. Thanks.
                    – Aquarelle
                    May 6 '14 at 21:58










                  • It worked in this scenario -> "echo "$SPLIT_0" | awk -F' inode=' '{print $1}'"! I had problems when trying to use atrings (" inode=") instead of characters (";"). $ 1, $ 2, $ 3, $ 4 are set as positions in an array! If there is a way of setting an array... better! Thanks!
                    – Eduardo Lucio
                    Aug 5 '15 at 12:59










                  • @EduardoLucio, what I'm thinking about is maybe you can first replace your delimiter inode= into ; for example by sed -i 's/inode=/;/g' your_file_to_process, then define -F';' when apply awk, hope that can help you.
                    – Tony
                    Aug 6 '15 at 2:42










                  2




                  2




                  Or even simpler: echo "bla@some.com;john@home.com" | awk 'BEGIN{RS=";"} {print}'
                  – Jaro
                  Jan 7 '14 at 21:30






                  Or even simpler: echo "bla@some.com;john@home.com" | awk 'BEGIN{RS=";"} {print}'
                  – Jaro
                  Jan 7 '14 at 21:30














                  @Jaro This worked perfectly for me when I had a string with commas and needed to reformat it into lines. Thanks.
                  – Aquarelle
                  May 6 '14 at 21:58




                  @Jaro This worked perfectly for me when I had a string with commas and needed to reformat it into lines. Thanks.
                  – Aquarelle
                  May 6 '14 at 21:58












                  It worked in this scenario -> "echo "$SPLIT_0" | awk -F' inode=' '{print $1}'"! I had problems when trying to use atrings (" inode=") instead of characters (";"). $ 1, $ 2, $ 3, $ 4 are set as positions in an array! If there is a way of setting an array... better! Thanks!
                  – Eduardo Lucio
                  Aug 5 '15 at 12:59




                  It worked in this scenario -> "echo "$SPLIT_0" | awk -F' inode=' '{print $1}'"! I had problems when trying to use atrings (" inode=") instead of characters (";"). $ 1, $ 2, $ 3, $ 4 are set as positions in an array! If there is a way of setting an array... better! Thanks!
                  – Eduardo Lucio
                  Aug 5 '15 at 12:59












                  @EduardoLucio, what I'm thinking about is maybe you can first replace your delimiter inode= into ; for example by sed -i 's/inode=/;/g' your_file_to_process, then define -F';' when apply awk, hope that can help you.
                  – Tony
                  Aug 6 '15 at 2:42






                  @EduardoLucio, what I'm thinking about is maybe you can first replace your delimiter inode= into ; for example by sed -i 's/inode=/;/g' your_file_to_process, then define -F';' when apply awk, hope that can help you.
                  – Tony
                  Aug 6 '15 at 2:42












                  up vote
                  26
                  down vote













                  A different take on Darron's answer, this is how I do it:



                  IN="bla@some.com;john@home.com"
                  read ADDR1 ADDR2 <<<$(IFS=";"; echo $IN)





                  share|improve this answer























                  • This doesn't work.
                    – ColinM
                    Sep 10 '11 at 0:31










                  • I think it does! Run the commands above and then "echo $ADDR1 ... $ADDR2" and i get "bla@some.com ... john@home.com" output
                    – nickjb
                    Oct 6 '11 at 15:33








                  • 1




                    This worked REALLY well for me... I used it to itterate over an array of strings which contained comma separated DB,SERVER,PORT data to use mysqldump.
                    – Nick
                    Oct 28 '11 at 14:36






                  • 5




                    Diagnosis: the IFS=";" assignment exists only in the $(...; echo $IN) subshell; this is why some readers (including me) initially think it won't work. I assumed that all of $IN was getting slurped up by ADDR1. But nickjb is correct; it does work. The reason is that echo $IN command parses its arguments using the current value of $IFS, but then echoes them to stdout using a space delimiter, regardless of the setting of $IFS. So the net effect is as though one had called read ADDR1 ADDR2 <<< "bla@some.com john@home.com" (note the input is space-separated not ;-separated).
                    – dubiousjim
                    May 31 '12 at 5:28








                  • 1




                    This fails on spaces and newlines, and also expand wildcards * in the echo $IN with an unquoted variable expansion.
                    – sorontar
                    Oct 26 '16 at 4:43















                  up vote
                  26
                  down vote













                  A different take on Darron's answer, this is how I do it:



                  IN="bla@some.com;john@home.com"
                  read ADDR1 ADDR2 <<<$(IFS=";"; echo $IN)





                  share|improve this answer























                  • This doesn't work.
                    – ColinM
                    Sep 10 '11 at 0:31










                  • I think it does! Run the commands above and then "echo $ADDR1 ... $ADDR2" and i get "bla@some.com ... john@home.com" output
                    – nickjb
                    Oct 6 '11 at 15:33








                  • 1




                    This worked REALLY well for me... I used it to itterate over an array of strings which contained comma separated DB,SERVER,PORT data to use mysqldump.
                    – Nick
                    Oct 28 '11 at 14:36






                  • 5




                    Diagnosis: the IFS=";" assignment exists only in the $(...; echo $IN) subshell; this is why some readers (including me) initially think it won't work. I assumed that all of $IN was getting slurped up by ADDR1. But nickjb is correct; it does work. The reason is that echo $IN command parses its arguments using the current value of $IFS, but then echoes them to stdout using a space delimiter, regardless of the setting of $IFS. So the net effect is as though one had called read ADDR1 ADDR2 <<< "bla@some.com john@home.com" (note the input is space-separated not ;-separated).
                    – dubiousjim
                    May 31 '12 at 5:28








                  • 1




                    This fails on spaces and newlines, and also expand wildcards * in the echo $IN with an unquoted variable expansion.
                    – sorontar
                    Oct 26 '16 at 4:43













                  up vote
                  26
                  down vote










                  up vote
                  26
                  down vote









                  A different take on Darron's answer, this is how I do it:



                  IN="bla@some.com;john@home.com"
                  read ADDR1 ADDR2 <<<$(IFS=";"; echo $IN)





                  share|improve this answer














                  A different take on Darron's answer, this is how I do it:



                  IN="bla@some.com;john@home.com"
                  read ADDR1 ADDR2 <<<$(IFS=";"; echo $IN)






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited May 23 '17 at 12:34









                  Community

                  11




                  11










                  answered Jul 5 '11 at 13:41









                  nickjb

                  611816




                  611816












                  • This doesn't work.
                    – ColinM
                    Sep 10 '11 at 0:31










                  • I think it does! Run the commands above and then "echo $ADDR1 ... $ADDR2" and i get "bla@some.com ... john@home.com" output
                    – nickjb
                    Oct 6 '11 at 15:33








                  • 1




                    This worked REALLY well for me... I used it to itterate over an array of strings which contained comma separated DB,SERVER,PORT data to use mysqldump.
                    – Nick
                    Oct 28 '11 at 14:36






                  • 5




                    Diagnosis: the IFS=";" assignment exists only in the $(...; echo $IN) subshell; this is why some readers (including me) initially think it won't work. I assumed that all of $IN was getting slurped up by ADDR1. But nickjb is correct; it does work. The reason is that echo $IN command parses its arguments using the current value of $IFS, but then echoes them to stdout using a space delimiter, regardless of the setting of $IFS. So the net effect is as though one had called read ADDR1 ADDR2 <<< "bla@some.com john@home.com" (note the input is space-separated not ;-separated).
                    – dubiousjim
                    May 31 '12 at 5:28








                  • 1




                    This fails on spaces and newlines, and also expand wildcards * in the echo $IN with an unquoted variable expansion.
                    – sorontar
                    Oct 26 '16 at 4:43


















                  • This doesn't work.
                    – ColinM
                    Sep 10 '11 at 0:31










                  • I think it does! Run the commands above and then "echo $ADDR1 ... $ADDR2" and i get "bla@some.com ... john@home.com" output
                    – nickjb
                    Oct 6 '11 at 15:33








                  • 1




                    This worked REALLY well for me... I used it to itterate over an array of strings which contained comma separated DB,SERVER,PORT data to use mysqldump.
                    – Nick
                    Oct 28 '11 at 14:36






                  • 5




                    Diagnosis: the IFS=";" assignment exists only in the $(...; echo $IN) subshell; this is why some readers (including me) initially think it won't work. I assumed that all of $IN was getting slurped up by ADDR1. But nickjb is correct; it does work. The reason is that echo $IN command parses its arguments using the current value of $IFS, but then echoes them to stdout using a space delimiter, regardless of the setting of $IFS. So the net effect is as though one had called read ADDR1 ADDR2 <<< "bla@some.com john@home.com" (note the input is space-separated not ;-separated).
                    – dubiousjim
                    May 31 '12 at 5:28








                  • 1




                    This fails on spaces and newlines, and also expand wildcards * in the echo $IN with an unquoted variable expansion.
                    – sorontar
                    Oct 26 '16 at 4:43
















                  This doesn't work.
                  – ColinM
                  Sep 10 '11 at 0:31




                  This doesn't work.
                  – ColinM
                  Sep 10 '11 at 0:31












                  I think it does! Run the commands above and then "echo $ADDR1 ... $ADDR2" and i get "bla@some.com ... john@home.com" output
                  – nickjb
                  Oct 6 '11 at 15:33






                  I think it does! Run the commands above and then "echo $ADDR1 ... $ADDR2" and i get "bla@some.com ... john@home.com" output
                  – nickjb
                  Oct 6 '11 at 15:33






                  1




                  1




                  This worked REALLY well for me... I used it to itterate over an array of strings which contained comma separated DB,SERVER,PORT data to use mysqldump.
                  – Nick
                  Oct 28 '11 at 14:36




                  This worked REALLY well for me... I used it to itterate over an array of strings which contained comma separated DB,SERVER,PORT data to use mysqldump.
                  – Nick
                  Oct 28 '11 at 14:36




                  5




                  5




                  Diagnosis: the IFS=";" assignment exists only in the $(...; echo $IN) subshell; this is why some readers (including me) initially think it won't work. I assumed that all of $IN was getting slurped up by ADDR1. But nickjb is correct; it does work. The reason is that echo $IN command parses its arguments using the current value of $IFS, but then echoes them to stdout using a space delimiter, regardless of the setting of $IFS. So the net effect is as though one had called read ADDR1 ADDR2 <<< "bla@some.com john@home.com" (note the input is space-separated not ;-separated).
                  – dubiousjim
                  May 31 '12 at 5:28






                  Diagnosis: the IFS=";" assignment exists only in the $(...; echo $IN) subshell; this is why some readers (including me) initially think it won't work. I assumed that all of $IN was getting slurped up by ADDR1. But nickjb is correct; it does work. The reason is that echo $IN command parses its arguments using the current value of $IFS, but then echoes them to stdout using a space delimiter, regardless of the setting of $IFS. So the net effect is as though one had called read ADDR1 ADDR2 <<< "bla@some.com john@home.com" (note the input is space-separated not ;-separated).
                  – dubiousjim
                  May 31 '12 at 5:28






                  1




                  1




                  This fails on spaces and newlines, and also expand wildcards * in the echo $IN with an unquoted variable expansion.
                  – sorontar
                  Oct 26 '16 at 4:43




                  This fails on spaces and newlines, and also expand wildcards * in the echo $IN with an unquoted variable expansion.
                  – sorontar
                  Oct 26 '16 at 4:43










                  up vote
                  24
                  down vote













                  In Bash, a bullet proof way, that will work even if your variable contains newlines:



                  IFS=';' read -d '' -ra array < <(printf '%s;' "$in")


                  Look:



                  $ in=$'one;two three;*;there isna newlinenin this field'
                  $ IFS=';' read -d '' -ra array < <(printf '%s;' "$in")
                  $ declare -p array
                  declare -a array='([0]="one" [1]="two three" [2]="*" [3]="there is
                  a newline
                  in this field")'


                  The trick for this to work is to use the -d option of read (delimiter) with an empty delimiter, so that read is forced to read everything it's fed. And we feed read with exactly the content of the variable in, with no trailing newline thanks to printf. Note that's we're also putting the delimiter in printf to ensure that the string passed to read has a trailing delimiter. Without it, read would trim potential trailing empty fields:



                  $ in='one;two;three;'    # there's an empty field
                  $ IFS=';' read -d '' -ra array < <(printf '%s;' "$in")
                  $ declare -p array
                  declare -a array='([0]="one" [1]="two" [2]="three" [3]="")'


                  the trailing empty field is preserved.





                  Update for Bash≥4.4



                  Since Bash 4.4, the builtin mapfile (aka readarray) supports the -d option to specify a delimiter. Hence another canonical way is:



                  mapfile -d ';' -t array < <(printf '%s;' "$in")





                  share|improve this answer



















                  • 4




                    I found it as the rare solution on that list that works correctly with n, spaces and * simultaneously. Also, no loops; array variable is accessible in the shell after execution (contrary to the highest upvoted answer). Note, in=$'...', it does not work with double quotes. I think, it needs more upvotes.
                    – John_West
                    Jan 8 '16 at 12:10

















                  up vote
                  24
                  down vote













                  In Bash, a bullet proof way, that will work even if your variable contains newlines:



                  IFS=';' read -d '' -ra array < <(printf '%s;' "$in")


                  Look:



                  $ in=$'one;two three;*;there isna newlinenin this field'
                  $ IFS=';' read -d '' -ra array < <(printf '%s;' "$in")
                  $ declare -p array
                  declare -a array='([0]="one" [1]="two three" [2]="*" [3]="there is
                  a newline
                  in this field")'


                  The trick for this to work is to use the -d option of read (delimiter) with an empty delimiter, so that read is forced to read everything it's fed. And we feed read with exactly the content of the variable in, with no trailing newline thanks to printf. Note that's we're also putting the delimiter in printf to ensure that the string passed to read has a trailing delimiter. Without it, read would trim potential trailing empty fields:



                  $ in='one;two;three;'    # there's an empty field
                  $ IFS=';' read -d '' -ra array < <(printf '%s;' "$in")
                  $ declare -p array
                  declare -a array='([0]="one" [1]="two" [2]="three" [3]="")'


                  the trailing empty field is preserved.





                  Update for Bash≥4.4



                  Since Bash 4.4, the builtin mapfile (aka readarray) supports the -d option to specify a delimiter. Hence another canonical way is:



                  mapfile -d ';' -t array < <(printf '%s;' "$in")





                  share|improve this answer



















                  • 4




                    I found it as the rare solution on that list that works correctly with n, spaces and * simultaneously. Also, no loops; array variable is accessible in the shell after execution (contrary to the highest upvoted answer). Note, in=$'...', it does not work with double quotes. I think, it needs more upvotes.
                    – John_West
                    Jan 8 '16 at 12:10















                  up vote
                  24
                  down vote










                  up vote
                  24
                  down vote









                  In Bash, a bullet proof way, that will work even if your variable contains newlines:



                  IFS=';' read -d '' -ra array < <(printf '%s;' "$in")


                  Look:



                  $ in=$'one;two three;*;there isna newlinenin this field'
                  $ IFS=';' read -d '' -ra array < <(printf '%s;' "$in")
                  $ declare -p array
                  declare -a array='([0]="one" [1]="two three" [2]="*" [3]="there is
                  a newline
                  in this field")'


                  The trick for this to work is to use the -d option of read (delimiter) with an empty delimiter, so that read is forced to read everything it's fed. And we feed read with exactly the content of the variable in, with no trailing newline thanks to printf. Note that's we're also putting the delimiter in printf to ensure that the string passed to read has a trailing delimiter. Without it, read would trim potential trailing empty fields:



                  $ in='one;two;three;'    # there's an empty field
                  $ IFS=';' read -d '' -ra array < <(printf '%s;' "$in")
                  $ declare -p array
                  declare -a array='([0]="one" [1]="two" [2]="three" [3]="")'


                  the trailing empty field is preserved.





                  Update for Bash≥4.4



                  Since Bash 4.4, the builtin mapfile (aka readarray) supports the -d option to specify a delimiter. Hence another canonical way is:



                  mapfile -d ';' -t array < <(printf '%s;' "$in")





                  share|improve this answer














                  In Bash, a bullet proof way, that will work even if your variable contains newlines:



                  IFS=';' read -d '' -ra array < <(printf '%s;' "$in")


                  Look:



                  $ in=$'one;two three;*;there isna newlinenin this field'
                  $ IFS=';' read -d '' -ra array < <(printf '%s;' "$in")
                  $ declare -p array
                  declare -a array='([0]="one" [1]="two three" [2]="*" [3]="there is
                  a newline
                  in this field")'


                  The trick for this to work is to use the -d option of read (delimiter) with an empty delimiter, so that read is forced to read everything it's fed. And we feed read with exactly the content of the variable in, with no trailing newline thanks to printf. Note that's we're also putting the delimiter in printf to ensure that the string passed to read has a trailing delimiter. Without it, read would trim potential trailing empty fields:



                  $ in='one;two;three;'    # there's an empty field
                  $ IFS=';' read -d '' -ra array < <(printf '%s;' "$in")
                  $ declare -p array
                  declare -a array='([0]="one" [1]="two" [2]="three" [3]="")'


                  the trailing empty field is preserved.





                  Update for Bash≥4.4



                  Since Bash 4.4, the builtin mapfile (aka readarray) supports the -d option to specify a delimiter. Hence another canonical way is:



                  mapfile -d ';' -t array < <(printf '%s;' "$in")






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Oct 27 '15 at 16:03

























                  answered Jun 26 '14 at 9:11









                  gniourf_gniourf

                  29.1k56283




                  29.1k56283








                  • 4




                    I found it as the rare solution on that list that works correctly with n, spaces and * simultaneously. Also, no loops; array variable is accessible in the shell after execution (contrary to the highest upvoted answer). Note, in=$'...', it does not work with double quotes. I think, it needs more upvotes.
                    – John_West
                    Jan 8 '16 at 12:10
















                  • 4




                    I found it as the rare solution on that list that works correctly with n, spaces and * simultaneously. Also, no loops; array variable is accessible in the shell after execution (contrary to the highest upvoted answer). Note, in=$'...', it does not work with double quotes. I think, it needs more upvotes.
                    – John_West
                    Jan 8 '16 at 12:10










                  4




                  4




                  I found it as the rare solution on that list that works correctly with n, spaces and * simultaneously. Also, no loops; array variable is accessible in the shell after execution (contrary to the highest upvoted answer). Note, in=$'...', it does not work with double quotes. I think, it needs more upvotes.
                  – John_West
                  Jan 8 '16 at 12:10






                  I found it as the rare solution on that list that works correctly with n, spaces and * simultaneously. Also, no loops; array variable is accessible in the shell after execution (contrary to the highest upvoted answer). Note, in=$'...', it does not work with double quotes. I think, it needs more upvotes.
                  – John_West
                  Jan 8 '16 at 12:10












                  up vote
                  18
                  down vote













                  How about this one liner, if you're not using arrays:



                  IFS=';' read ADDR1 ADDR2 <<<$IN





                  share|improve this answer





















                  • Consider using read -r ... to ensure that, for example, the two characters "t" in the input end up as the same two characters in your variables (instead of a single tab char).
                    – dubiousjim
                    May 31 '12 at 5:36










                  • -1 This is not working here (ubuntu 12.04). Adding echo "ADDR1 $ADDR1"n echo "ADDR2 $ADDR2" to your snippet will output ADDR1 bla@some.com john@home.comnADDR2 (n is newline)
                    – Luca Borrione
                    Sep 3 '12 at 10:07










                  • This is probably due to a bug involving IFS and here strings that was fixed in bash 4.3. Quoting $IN should fix it. (In theory, $IN is not subject to word splitting or globbing after it expands, meaning the quotes should be unnecessary. Even in 4.3, though, there's at least one bug remaining--reported and scheduled to be fixed--so quoting remains a good idea.)
                    – chepner
                    Sep 19 '15 at 13:59










                  • This breaks if $in contain newlines even if $IN is quoted. And adds a trailing newline.
                    – sorontar
                    Oct 26 '16 at 4:55















                  up vote
                  18
                  down vote













                  How about this one liner, if you're not using arrays:



                  IFS=';' read ADDR1 ADDR2 <<<$IN





                  share|improve this answer





















                  • Consider using read -r ... to ensure that, for example, the two characters "t" in the input end up as the same two characters in your variables (instead of a single tab char).
                    – dubiousjim
                    May 31 '12 at 5:36










                  • -1 This is not working here (ubuntu 12.04). Adding echo "ADDR1 $ADDR1"n echo "ADDR2 $ADDR2" to your snippet will output ADDR1 bla@some.com john@home.comnADDR2 (n is newline)
                    – Luca Borrione
                    Sep 3 '12 at 10:07










                  • This is probably due to a bug involving IFS and here strings that was fixed in bash 4.3. Quoting $IN should fix it. (In theory, $IN is not subject to word splitting or globbing after it expands, meaning the quotes should be unnecessary. Even in 4.3, though, there's at least one bug remaining--reported and scheduled to be fixed--so quoting remains a good idea.)
                    – chepner
                    Sep 19 '15 at 13:59










                  • This breaks if $in contain newlines even if $IN is quoted. And adds a trailing newline.
                    – sorontar
                    Oct 26 '16 at 4:55













                  up vote
                  18
                  down vote










                  up vote
                  18
                  down vote









                  How about this one liner, if you're not using arrays:



                  IFS=';' read ADDR1 ADDR2 <<<$IN





                  share|improve this answer












                  How about this one liner, if you're not using arrays:



                  IFS=';' read ADDR1 ADDR2 <<<$IN






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Sep 13 '10 at 20:10









                  Darron

                  18.8k54352




                  18.8k54352












                  • Consider using read -r ... to ensure that, for example, the two characters "t" in the input end up as the same two characters in your variables (instead of a single tab char).
                    – dubiousjim
                    May 31 '12 at 5:36










                  • -1 This is not working here (ubuntu 12.04). Adding echo "ADDR1 $ADDR1"n echo "ADDR2 $ADDR2" to your snippet will output ADDR1 bla@some.com john@home.comnADDR2 (n is newline)
                    – Luca Borrione
                    Sep 3 '12 at 10:07










                  • This is probably due to a bug involving IFS and here strings that was fixed in bash 4.3. Quoting $IN should fix it. (In theory, $IN is not subject to word splitting or globbing after it expands, meaning the quotes should be unnecessary. Even in 4.3, though, there's at least one bug remaining--reported and scheduled to be fixed--so quoting remains a good idea.)
                    – chepner
                    Sep 19 '15 at 13:59










                  • This breaks if $in contain newlines even if $IN is quoted. And adds a trailing newline.
                    – sorontar
                    Oct 26 '16 at 4:55


















                  • Consider using read -r ... to ensure that, for example, the two characters "t" in the input end up as the same two characters in your variables (instead of a single tab char).
                    – dubiousjim
                    May 31 '12 at 5:36










                  • -1 This is not working here (ubuntu 12.04). Adding echo "ADDR1 $ADDR1"n echo "ADDR2 $ADDR2" to your snippet will output ADDR1 bla@some.com john@home.comnADDR2 (n is newline)
                    – Luca Borrione
                    Sep 3 '12 at 10:07










                  • This is probably due to a bug involving IFS and here strings that was fixed in bash 4.3. Quoting $IN should fix it. (In theory, $IN is not subject to word splitting or globbing after it expands, meaning the quotes should be unnecessary. Even in 4.3, though, there's at least one bug remaining--reported and scheduled to be fixed--so quoting remains a good idea.)
                    – chepner
                    Sep 19 '15 at 13:59










                  • This breaks if $in contain newlines even if $IN is quoted. And adds a trailing newline.
                    – sorontar
                    Oct 26 '16 at 4:55
















                  Consider using read -r ... to ensure that, for example, the two characters "t" in the input end up as the same two characters in your variables (instead of a single tab char).
                  – dubiousjim
                  May 31 '12 at 5:36




                  Consider using read -r ... to ensure that, for example, the two characters "t" in the input end up as the same two characters in your variables (instead of a single tab char).
                  – dubiousjim
                  May 31 '12 at 5:36












                  -1 This is not working here (ubuntu 12.04). Adding echo "ADDR1 $ADDR1"n echo "ADDR2 $ADDR2" to your snippet will output ADDR1 bla@some.com john@home.comnADDR2 (n is newline)
                  – Luca Borrione
                  Sep 3 '12 at 10:07




                  -1 This is not working here (ubuntu 12.04). Adding echo "ADDR1 $ADDR1"n echo "ADDR2 $ADDR2" to your snippet will output ADDR1 bla@some.com john@home.comnADDR2 (n is newline)
                  – Luca Borrione
                  Sep 3 '12 at 10:07












                  This is probably due to a bug involving IFS and here strings that was fixed in bash 4.3. Quoting $IN should fix it. (In theory, $IN is not subject to word splitting or globbing after it expands, meaning the quotes should be unnecessary. Even in 4.3, though, there's at least one bug remaining--reported and scheduled to be fixed--so quoting remains a good idea.)
                  – chepner
                  Sep 19 '15 at 13:59




                  This is probably due to a bug involving IFS and here strings that was fixed in bash 4.3. Quoting $IN should fix it. (In theory, $IN is not subject to word splitting or globbing after it expands, meaning the quotes should be unnecessary. Even in 4.3, though, there's at least one bug remaining--reported and scheduled to be fixed--so quoting remains a good idea.)
                  – chepner
                  Sep 19 '15 at 13:59












                  This breaks if $in contain newlines even if $IN is quoted. And adds a trailing newline.
                  – sorontar
                  Oct 26 '16 at 4:55




                  This breaks if $in contain newlines even if $IN is quoted. And adds a trailing newline.
                  – sorontar
                  Oct 26 '16 at 4:55










                  up vote
                  17
                  down vote













                  Here is a clean 3-liner:



                  in="foo@bar;bizz@buzz;fizz@buzz;buzz@woof"
                  IFS=';' list=($in)
                  for item in "${list[@]}"; do echo $item; done


                  where IFS delimit words based on the separator and () is used to create an array. Then [@] is used to return each item as a separate word.



                  If you've any code after that, you also need to restore $IFS, e.g. unset IFS.






                  share|improve this answer



















                  • 4




                    The use of $in unquoted allows wildcards to be expanded.
                    – sorontar
                    Oct 26 '16 at 5:03






                  • 1




                    + for the unset command
                    – user2720864
                    Sep 24 at 13:46















                  up vote
                  17
                  down vote













                  Here is a clean 3-liner:



                  in="foo@bar;bizz@buzz;fizz@buzz;buzz@woof"
                  IFS=';' list=($in)
                  for item in "${list[@]}"; do echo $item; done


                  where IFS delimit words based on the separator and () is used to create an array. Then [@] is used to return each item as a separate word.



                  If you've any code after that, you also need to restore $IFS, e.g. unset IFS.






                  share|improve this answer



















                  • 4




                    The use of $in unquoted allows wildcards to be expanded.
                    – sorontar
                    Oct 26 '16 at 5:03






                  • 1




                    + for the unset command
                    – user2720864
                    Sep 24 at 13:46













                  up vote
                  17
                  down vote










                  up vote
                  17
                  down vote









                  Here is a clean 3-liner:



                  in="foo@bar;bizz@buzz;fizz@buzz;buzz@woof"
                  IFS=';' list=($in)
                  for item in "${list[@]}"; do echo $item; done


                  where IFS delimit words based on the separator and () is used to create an array. Then [@] is used to return each item as a separate word.



                  If you've any code after that, you also need to restore $IFS, e.g. unset IFS.






                  share|improve this answer














                  Here is a clean 3-liner:



                  in="foo@bar;bizz@buzz;fizz@buzz;buzz@woof"
                  IFS=';' list=($in)
                  for item in "${list[@]}"; do echo $item; done


                  where IFS delimit words based on the separator and () is used to create an array. Then [@] is used to return each item as a separate word.



                  If you've any code after that, you also need to restore $IFS, e.g. unset IFS.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Oct 26 '16 at 10:26

























                  answered Sep 11 '15 at 20:54









                  kenorb

                  62.9k27377386




                  62.9k27377386








                  • 4




                    The use of $in unquoted allows wildcards to be expanded.
                    – sorontar
                    Oct 26 '16 at 5:03






                  • 1




                    + for the unset command
                    – user2720864
                    Sep 24 at 13:46














                  • 4




                    The use of $in unquoted allows wildcards to be expanded.
                    – sorontar
                    Oct 26 '16 at 5:03






                  • 1




                    + for the unset command
                    – user2720864
                    Sep 24 at 13:46








                  4




                  4




                  The use of $in unquoted allows wildcards to be expanded.
                  – sorontar
                  Oct 26 '16 at 5:03




                  The use of $in unquoted allows wildcards to be expanded.
                  – sorontar
                  Oct 26 '16 at 5:03




                  1




                  1




                  + for the unset command
                  – user2720864
                  Sep 24 at 13:46




                  + for the unset command
                  – user2720864
                  Sep 24 at 13:46










                  up vote
                  16
                  down vote













                  Without setting the IFS



                  If you just have one colon you can do that:



                  a="foo:bar"
                  b=${a%:*}
                  c=${a##*:}


                  you will get:



                  b = foo
                  c = bar





                  share|improve this answer

























                    up vote
                    16
                    down vote













                    Without setting the IFS



                    If you just have one colon you can do that:



                    a="foo:bar"
                    b=${a%:*}
                    c=${a##*:}


                    you will get:



                    b = foo
                    c = bar





                    share|improve this answer























                      up vote
                      16
                      down vote










                      up vote
                      16
                      down vote









                      Without setting the IFS



                      If you just have one colon you can do that:



                      a="foo:bar"
                      b=${a%:*}
                      c=${a##*:}


                      you will get:



                      b = foo
                      c = bar





                      share|improve this answer












                      Without setting the IFS



                      If you just have one colon you can do that:



                      a="foo:bar"
                      b=${a%:*}
                      c=${a##*:}


                      you will get:



                      b = foo
                      c = bar






                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Aug 1 '16 at 13:15









                      Emilien Brigand

                      2,34742329




                      2,34742329






















                          up vote
                          7
                          down vote













                          There is a simple and smart way like this:



                          echo "add:sfff" | xargs -d: -i  echo {}


                          But you must use gnu xargs, BSD xargs cant support -d delim. If you use apple mac like me. You can install gnu xargs :



                          brew install findutils


                          then



                          echo "add:sfff" | gxargs -d: -i  echo {}





                          share|improve this answer

























                            up vote
                            7
                            down vote













                            There is a simple and smart way like this:



                            echo "add:sfff" | xargs -d: -i  echo {}


                            But you must use gnu xargs, BSD xargs cant support -d delim. If you use apple mac like me. You can install gnu xargs :



                            brew install findutils


                            then



                            echo "add:sfff" | gxargs -d: -i  echo {}





                            share|improve this answer























                              up vote
                              7
                              down vote










                              up vote
                              7
                              down vote









                              There is a simple and smart way like this:



                              echo "add:sfff" | xargs -d: -i  echo {}


                              But you must use gnu xargs, BSD xargs cant support -d delim. If you use apple mac like me. You can install gnu xargs :



                              brew install findutils


                              then



                              echo "add:sfff" | gxargs -d: -i  echo {}





                              share|improve this answer












                              There is a simple and smart way like this:



                              echo "add:sfff" | xargs -d: -i  echo {}


                              But you must use gnu xargs, BSD xargs cant support -d delim. If you use apple mac like me. You can install gnu xargs :



                              brew install findutils


                              then



                              echo "add:sfff" | gxargs -d: -i  echo {}






                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Sep 16 '15 at 3:34









                              Victor Choy

                              1,3901220




                              1,3901220






















                                  up vote
                                  5
                                  down vote













                                  The following Bash/zsh function splits its first argument on the delimiter given by the second argument:



                                  split() {
                                  local string="$1"
                                  local delimiter="$2"
                                  if [ -n "$string" ]; then
                                  local part
                                  while read -d "$delimiter" part; do
                                  echo $part
                                  done <<< "$string"
                                  echo $part
                                  fi
                                  }


                                  For instance, the command



                                  $ split 'a;b;c' ';'


                                  yields



                                  a
                                  b
                                  c


                                  This output may, for instance, be piped to other commands. Example:



                                  $ split 'a;b;c' ';' | cat -n
                                  1 a
                                  2 b
                                  3 c


                                  Compared to the other solutions given, this one has the following advantages:




                                  • IFS is not overriden: Due to dynamic scoping of even local variables, overriding IFS over a loop causes the new value to leak into function calls performed from within the loop.


                                  • Arrays are not used: Reading a string into an array using read requires the flag -a in Bash and -A in zsh.



                                  If desired, the function may be put into a script as follows:



                                  #!/usr/bin/env bash

                                  split() {
                                  # ...
                                  }

                                  split "$@"





                                  share|improve this answer























                                  • works and neatly modularized.
                                    – sandeepkunkunuru
                                    Oct 23 '17 at 16:10















                                  up vote
                                  5
                                  down vote













                                  The following Bash/zsh function splits its first argument on the delimiter given by the second argument:



                                  split() {
                                  local string="$1"
                                  local delimiter="$2"
                                  if [ -n "$string" ]; then
                                  local part
                                  while read -d "$delimiter" part; do
                                  echo $part
                                  done <<< "$string"
                                  echo $part
                                  fi
                                  }


                                  For instance, the command



                                  $ split 'a;b;c' ';'


                                  yields



                                  a
                                  b
                                  c


                                  This output may, for instance, be piped to other commands. Example:



                                  $ split 'a;b;c' ';' | cat -n
                                  1 a
                                  2 b
                                  3 c


                                  Compared to the other solutions given, this one has the following advantages:




                                  • IFS is not overriden: Due to dynamic scoping of even local variables, overriding IFS over a loop causes the new value to leak into function calls performed from within the loop.


                                  • Arrays are not used: Reading a string into an array using read requires the flag -a in Bash and -A in zsh.



                                  If desired, the function may be put into a script as follows:



                                  #!/usr/bin/env bash

                                  split() {
                                  # ...
                                  }

                                  split "$@"





                                  share|improve this answer























                                  • works and neatly modularized.
                                    – sandeepkunkunuru
                                    Oct 23 '17 at 16:10













                                  up vote
                                  5
                                  down vote










                                  up vote
                                  5
                                  down vote









                                  The following Bash/zsh function splits its first argument on the delimiter given by the second argument:



                                  split() {
                                  local string="$1"
                                  local delimiter="$2"
                                  if [ -n "$string" ]; then
                                  local part
                                  while read -d "$delimiter" part; do
                                  echo $part
                                  done <<< "$string"
                                  echo $part
                                  fi
                                  }


                                  For instance, the command



                                  $ split 'a;b;c' ';'


                                  yields



                                  a
                                  b
                                  c


                                  This output may, for instance, be piped to other commands. Example:



                                  $ split 'a;b;c' ';' | cat -n
                                  1 a
                                  2 b
                                  3 c


                                  Compared to the other solutions given, this one has the following advantages:




                                  • IFS is not overriden: Due to dynamic scoping of even local variables, overriding IFS over a loop causes the new value to leak into function calls performed from within the loop.


                                  • Arrays are not used: Reading a string into an array using read requires the flag -a in Bash and -A in zsh.



                                  If desired, the function may be put into a script as follows:



                                  #!/usr/bin/env bash

                                  split() {
                                  # ...
                                  }

                                  split "$@"





                                  share|improve this answer














                                  The following Bash/zsh function splits its first argument on the delimiter given by the second argument:



                                  split() {
                                  local string="$1"
                                  local delimiter="$2"
                                  if [ -n "$string" ]; then
                                  local part
                                  while read -d "$delimiter" part; do
                                  echo $part
                                  done <<< "$string"
                                  echo $part
                                  fi
                                  }


                                  For instance, the command



                                  $ split 'a;b;c' ';'


                                  yields



                                  a
                                  b
                                  c


                                  This output may, for instance, be piped to other commands. Example:



                                  $ split 'a;b;c' ';' | cat -n
                                  1 a
                                  2 b
                                  3 c


                                  Compared to the other solutions given, this one has the following advantages:




                                  • IFS is not overriden: Due to dynamic scoping of even local variables, overriding IFS over a loop causes the new value to leak into function calls performed from within the loop.


                                  • Arrays are not used: Reading a string into an array using read requires the flag -a in Bash and -A in zsh.



                                  If desired, the function may be put into a script as follows:



                                  #!/usr/bin/env bash

                                  split() {
                                  # ...
                                  }

                                  split "$@"






                                  share|improve this answer














                                  share|improve this answer



                                  share|improve this answer








                                  edited Jun 13 '17 at 18:24

























                                  answered May 24 '17 at 8:42









                                  Halle Knast

                                  1,94231928




                                  1,94231928












                                  • works and neatly modularized.
                                    – sandeepkunkunuru
                                    Oct 23 '17 at 16:10


















                                  • works and neatly modularized.
                                    – sandeepkunkunuru
                                    Oct 23 '17 at 16:10
















                                  works and neatly modularized.
                                  – sandeepkunkunuru
                                  Oct 23 '17 at 16:10




                                  works and neatly modularized.
                                  – sandeepkunkunuru
                                  Oct 23 '17 at 16:10










                                  up vote
                                  4
                                  down vote













                                  This is the simplest way to do it.



                                  spo='one;two;three'
                                  OIFS=$IFS
                                  IFS=';'
                                  spo_array=($spo)
                                  IFS=$OIFS
                                  echo ${spo_array[*]}





                                  share|improve this answer



























                                    up vote
                                    4
                                    down vote













                                    This is the simplest way to do it.



                                    spo='one;two;three'
                                    OIFS=$IFS
                                    IFS=';'
                                    spo_array=($spo)
                                    IFS=$OIFS
                                    echo ${spo_array[*]}





                                    share|improve this answer

























                                      up vote
                                      4
                                      down vote










                                      up vote
                                      4
                                      down vote









                                      This is the simplest way to do it.



                                      spo='one;two;three'
                                      OIFS=$IFS
                                      IFS=';'
                                      spo_array=($spo)
                                      IFS=$OIFS
                                      echo ${spo_array[*]}





                                      share|improve this answer














                                      This is the simplest way to do it.



                                      spo='one;two;three'
                                      OIFS=$IFS
                                      IFS=';'
                                      spo_array=($spo)
                                      IFS=$OIFS
                                      echo ${spo_array[*]}






                                      share|improve this answer














                                      share|improve this answer



                                      share|improve this answer








                                      edited Feb 28 '12 at 8:18

























                                      answered Sep 25 '11 at 1:09









                                      Prospero

                                      8,496133764




                                      8,496133764






















                                          up vote
                                          3
                                          down vote













                                          IN="bla@some.com;john@home.com"
                                          IFS=';'
                                          read -a IN_arr <<< "${IN}"
                                          for entry in "${IN_arr[@]}"
                                          do
                                          echo $entry
                                          done


                                          Output



                                          bla@some.com
                                          john@home.com


                                          System : Ubuntu 12.04.1






                                          share|improve this answer























                                          • IFS is not getting set in the specific context of read here and hence it can upset rest of the code, if any.
                                            – codeforester
                                            Jan 2 '17 at 5:37















                                          up vote
                                          3
                                          down vote













                                          IN="bla@some.com;john@home.com"
                                          IFS=';'
                                          read -a IN_arr <<< "${IN}"
                                          for entry in "${IN_arr[@]}"
                                          do
                                          echo $entry
                                          done


                                          Output



                                          bla@some.com
                                          john@home.com


                                          System : Ubuntu 12.04.1






                                          share|improve this answer























                                          • IFS is not getting set in the specific context of read here and hence it can upset rest of the code, if any.
                                            – codeforester
                                            Jan 2 '17 at 5:37













                                          up vote
                                          3
                                          down vote










                                          up vote
                                          3
                                          down vote









                                          IN="bla@some.com;john@home.com"
                                          IFS=';'
                                          read -a IN_arr <<< "${IN}"
                                          for entry in "${IN_arr[@]}"
                                          do
                                          echo $entry
                                          done


                                          Output



                                          bla@some.com
                                          john@home.com


                                          System : Ubuntu 12.04.1






                                          share|improve this answer














                                          IN="bla@some.com;john@home.com"
                                          IFS=';'
                                          read -a IN_arr <<< "${IN}"
                                          for entry in "${IN_arr[@]}"
                                          do
                                          echo $entry
                                          done


                                          Output



                                          bla@some.com
                                          john@home.com


                                          System : Ubuntu 12.04.1







                                          share|improve this answer














                                          share|improve this answer



                                          share|improve this answer








                                          edited Oct 25 '16 at 12:55

























                                          answered Oct 25 '16 at 12:41









                                          rashok

                                          5,980115475




                                          5,980115475












                                          • IFS is not getting set in the specific context of read here and hence it can upset rest of the code, if any.
                                            – codeforester
                                            Jan 2 '17 at 5:37


















                                          • IFS is not getting set in the specific context of read here and hence it can upset rest of the code, if any.
                                            – codeforester
                                            Jan 2 '17 at 5:37
















                                          IFS is not getting set in the specific context of read here and hence it can upset rest of the code, if any.
                                          – codeforester
                                          Jan 2 '17 at 5:37




                                          IFS is not getting set in the specific context of read here and hence it can upset rest of the code, if any.
                                          – codeforester
                                          Jan 2 '17 at 5:37










                                          up vote
                                          3
                                          down vote













                                          you can apply awk to many situations



                                          echo "bla@some.com;john@home.com"|awk -F';' '{printf "%sn%sn", $1, $2}'


                                          also you can use this



                                          echo "bla@some.com;john@home.com"|awk -F';' '{print $1,$2}' OFS="n"





                                          share|improve this answer



























                                            up vote
                                            3
                                            down vote













                                            you can apply awk to many situations



                                            echo "bla@some.com;john@home.com"|awk -F';' '{printf "%sn%sn", $1, $2}'


                                            also you can use this



                                            echo "bla@some.com;john@home.com"|awk -F';' '{print $1,$2}' OFS="n"





                                            share|improve this answer

























                                              up vote
                                              3
                                              down vote










                                              up vote
                                              3
                                              down vote









                                              you can apply awk to many situations



                                              echo "bla@some.com;john@home.com"|awk -F';' '{printf "%sn%sn", $1, $2}'


                                              also you can use this



                                              echo "bla@some.com;john@home.com"|awk -F';' '{print $1,$2}' OFS="n"





                                              share|improve this answer














                                              you can apply awk to many situations



                                              echo "bla@some.com;john@home.com"|awk -F';' '{printf "%sn%sn", $1, $2}'


                                              also you can use this



                                              echo "bla@some.com;john@home.com"|awk -F';' '{print $1,$2}' OFS="n"






                                              share|improve this answer














                                              share|improve this answer



                                              share|improve this answer








                                              edited Jan 21 at 11:34

























                                              answered Jan 20 at 15:54









                                              shuaihanhungry

                                              1393




                                              1393






















                                                  up vote
                                                  2
                                                  down vote













                                                  If no space, Why not this?



                                                  IN="bla@some.com;john@home.com"
                                                  arr=(`echo $IN | tr ';' ' '`)

                                                  echo ${arr[0]}
                                                  echo ${arr[1]}





                                                  share|improve this answer

























                                                    up vote
                                                    2
                                                    down vote













                                                    If no space, Why not this?



                                                    IN="bla@some.com;john@home.com"
                                                    arr=(`echo $IN | tr ';' ' '`)

                                                    echo ${arr[0]}
                                                    echo ${arr[1]}





                                                    share|improve this answer























                                                      up vote
                                                      2
                                                      down vote










                                                      up vote
                                                      2
                                                      down vote









                                                      If no space, Why not this?



                                                      IN="bla@some.com;john@home.com"
                                                      arr=(`echo $IN | tr ';' ' '`)

                                                      echo ${arr[0]}
                                                      echo ${arr[1]}





                                                      share|improve this answer












                                                      If no space, Why not this?



                                                      IN="bla@some.com;john@home.com"
                                                      arr=(`echo $IN | tr ';' ' '`)

                                                      echo ${arr[0]}
                                                      echo ${arr[1]}






                                                      share|improve this answer












                                                      share|improve this answer



                                                      share|improve this answer










                                                      answered Apr 24 '13 at 13:13









                                                      ghost

                                                      183210




                                                      183210






















                                                          up vote
                                                          2
                                                          down vote













                                                          Two bourne-ish alternatives where neither require bash arrays:



                                                          Case 1: Keep it nice and simple: Use a NewLine as the Record-Separator... eg.



                                                          IN="bla@some.com
                                                          john@home.com"

                                                          while read i; do
                                                          # process "$i" ... eg.
                                                          echo "[email:$i]"
                                                          done <<< "$IN"


                                                          Note: in this first case no sub-process is forked to assist with list manipulation.



                                                          Idea: Maybe it is worth using NL extensively internally, and only converting to a different RS when generating the final result externally.



                                                          Case 2: Using a ";" as a record separator... eg.



                                                          NL="
                                                          " IRS=";" ORS=";"

                                                          conv_IRS() {
                                                          exec tr "$1" "$NL"
                                                          }

                                                          conv_ORS() {
                                                          exec tr "$NL" "$1"
                                                          }

                                                          IN="bla@some.com;john@home.com"
                                                          IN="$(conv_IRS ";" <<< "$IN")"

                                                          while read i; do
                                                          # process "$i" ... eg.
                                                          echo -n "[email:$i]$ORS"
                                                          done <<< "$IN"


                                                          In both cases a sub-list can be composed within the loop is persistent after the loop has completed. This is useful when manipulating lists in memory, instead storing lists in files. {p.s. keep calm and carry on B-) }






                                                          share|improve this answer



























                                                            up vote
                                                            2
                                                            down vote













                                                            Two bourne-ish alternatives where neither require bash arrays:



                                                            Case 1: Keep it nice and simple: Use a NewLine as the Record-Separator... eg.



                                                            IN="bla@some.com
                                                            john@home.com"

                                                            while read i; do
                                                            # process "$i" ... eg.
                                                            echo "[email:$i]"
                                                            done <<< "$IN"


                                                            Note: in this first case no sub-process is forked to assist with list manipulation.



                                                            Idea: Maybe it is worth using NL extensively internally, and only converting to a different RS when generating the final result externally.



                                                            Case 2: Using a ";" as a record separator... eg.



                                                            NL="
                                                            " IRS=";" ORS=";"

                                                            conv_IRS() {
                                                            exec tr "$1" "$NL"
                                                            }

                                                            conv_ORS() {
                                                            exec tr "$NL" "$1"
                                                            }

                                                            IN="bla@some.com;john@home.com"
                                                            IN="$(conv_IRS ";" <<< "$IN")"

                                                            while read i; do
                                                            # process "$i" ... eg.
                                                            echo -n "[email:$i]$ORS"
                                                            done <<< "$IN"


                                                            In both cases a sub-list can be composed within the loop is persistent after the loop has completed. This is useful when manipulating lists in memory, instead storing lists in files. {p.s. keep calm and carry on B-) }






                                                            share|improve this answer

























                                                              up vote
                                                              2
                                                              down vote










                                                              up vote
                                                              2
                                                              down vote









                                                              Two bourne-ish alternatives where neither require bash arrays:



                                                              Case 1: Keep it nice and simple: Use a NewLine as the Record-Separator... eg.



                                                              IN="bla@some.com
                                                              john@home.com"

                                                              while read i; do
                                                              # process "$i" ... eg.
                                                              echo "[email:$i]"
                                                              done <<< "$IN"


                                                              Note: in this first case no sub-process is forked to assist with list manipulation.



                                                              Idea: Maybe it is worth using NL extensively internally, and only converting to a different RS when generating the final result externally.



                                                              Case 2: Using a ";" as a record separator... eg.



                                                              NL="
                                                              " IRS=";" ORS=";"

                                                              conv_IRS() {
                                                              exec tr "$1" "$NL"
                                                              }

                                                              conv_ORS() {
                                                              exec tr "$NL" "$1"
                                                              }

                                                              IN="bla@some.com;john@home.com"
                                                              IN="$(conv_IRS ";" <<< "$IN")"

                                                              while read i; do
                                                              # process "$i" ... eg.
                                                              echo -n "[email:$i]$ORS"
                                                              done <<< "$IN"


                                                              In both cases a sub-list can be composed within the loop is persistent after the loop has completed. This is useful when manipulating lists in memory, instead storing lists in files. {p.s. keep calm and carry on B-) }






                                                              share|improve this answer














                                                              Two bourne-ish alternatives where neither require bash arrays:



                                                              Case 1: Keep it nice and simple: Use a NewLine as the Record-Separator... eg.



                                                              IN="bla@some.com
                                                              john@home.com"

                                                              while read i; do
                                                              # process "$i" ... eg.
                                                              echo "[email:$i]"
                                                              done <<< "$IN"


                                                              Note: in this first case no sub-process is forked to assist with list manipulation.



                                                              Idea: Maybe it is worth using NL extensively internally, and only converting to a different RS when generating the final result externally.



                                                              Case 2: Using a ";" as a record separator... eg.



                                                              NL="
                                                              " IRS=";" ORS=";"

                                                              conv_IRS() {
                                                              exec tr "$1" "$NL"
                                                              }

                                                              conv_ORS() {
                                                              exec tr "$NL" "$1"
                                                              }

                                                              IN="bla@some.com;john@home.com"
                                                              IN="$(conv_IRS ";" <<< "$IN")"

                                                              while read i; do
                                                              # process "$i" ... eg.
                                                              echo -n "[email:$i]$ORS"
                                                              done <<< "$IN"


                                                              In both cases a sub-list can be composed within the loop is persistent after the loop has completed. This is useful when manipulating lists in memory, instead storing lists in files. {p.s. keep calm and carry on B-) }







                                                              share|improve this answer














                                                              share|improve this answer



                                                              share|improve this answer








                                                              edited Sep 2 '13 at 6:45

























                                                              answered Sep 2 '13 at 6:30









                                                              NevilleDNZ

                                                              732726




                                                              732726






















                                                                  up vote
                                                                  2
                                                                  down vote













                                                                  There are some cool answers here (errator esp.), but for something analogous to split in other languages -- which is what I took the original question to mean -- I settled on this:



                                                                  IN="bla@some.com;john@home.com"
                                                                  declare -a a="(${IN/;/ })";


                                                                  Now ${a[0]}, ${a[1]}, etc, are as you would expect. Use ${#a[*]} for number of terms. Or to iterate, of course:



                                                                  for i in ${a[*]}; do echo $i; done


                                                                  IMPORTANT NOTE:



                                                                  This works in cases where there are no spaces to worry about, which solved my problem, but may not solve yours. Go with the $IFS solution(s) in that case.






                                                                  share|improve this answer























                                                                  • Does not work when IN contains more than two e-mail addresses. Please refer to same idea (but fixed) at palindrom's answer
                                                                    – olibre
                                                                    Oct 7 '13 at 13:33












                                                                  • Better use ${IN//;/ } (double slash) to make it also work with more than two values. Beware that any wildcard (*?[) will be expanded. And a trailing empty field will be discarded.
                                                                    – sorontar
                                                                    Oct 26 '16 at 5:14















                                                                  up vote
                                                                  2
                                                                  down vote













                                                                  There are some cool answers here (errator esp.), but for something analogous to split in other languages -- which is what I took the original question to mean -- I settled on this:



                                                                  IN="bla@some.com;john@home.com"
                                                                  declare -a a="(${IN/;/ })";


                                                                  Now ${a[0]}, ${a[1]}, etc, are as you would expect. Use ${#a[*]} for number of terms. Or to iterate, of course:



                                                                  for i in ${a[*]}; do echo $i; done


                                                                  IMPORTANT NOTE:



                                                                  This works in cases where there are no spaces to worry about, which solved my problem, but may not solve yours. Go with the $IFS solution(s) in that case.






                                                                  share|improve this answer























                                                                  • Does not work when IN contains more than two e-mail addresses. Please refer to same idea (but fixed) at palindrom's answer
                                                                    – olibre
                                                                    Oct 7 '13 at 13:33












                                                                  • Better use ${IN//;/ } (double slash) to make it also work with more than two values. Beware that any wildcard (*?[) will be expanded. And a trailing empty field will be discarded.
                                                                    – sorontar
                                                                    Oct 26 '16 at 5:14













                                                                  up vote
                                                                  2
                                                                  down vote










                                                                  up vote
                                                                  2
                                                                  down vote









                                                                  There are some cool answers here (errator esp.), but for something analogous to split in other languages -- which is what I took the original question to mean -- I settled on this:



                                                                  IN="bla@some.com;john@home.com"
                                                                  declare -a a="(${IN/;/ })";


                                                                  Now ${a[0]}, ${a[1]}, etc, are as you would expect. Use ${#a[*]} for number of terms. Or to iterate, of course:



                                                                  for i in ${a[*]}; do echo $i; done


                                                                  IMPORTANT NOTE:



                                                                  This works in cases where there are no spaces to worry about, which solved my problem, but may not solve yours. Go with the $IFS solution(s) in that case.






                                                                  share|improve this answer














                                                                  There are some cool answers here (errator esp.), but for something analogous to split in other languages -- which is what I took the original question to mean -- I settled on this:



                                                                  IN="bla@some.com;john@home.com"
                                                                  declare -a a="(${IN/;/ })";


                                                                  Now ${a[0]}, ${a[1]}, etc, are as you would expect. Use ${#a[*]} for number of terms. Or to iterate, of course:



                                                                  for i in ${a[*]}; do echo $i; done


                                                                  IMPORTANT NOTE:



                                                                  This works in cases where there are no spaces to worry about, which solved my problem, but may not solve yours. Go with the $IFS solution(s) in that case.







                                                                  share|improve this answer














                                                                  share|improve this answer



                                                                  share|improve this answer








                                                                  edited Jan 21 '17 at 20:50









                                                                  Benjamin W.

                                                                  19.8k124554




                                                                  19.8k124554










                                                                  answered Oct 22 '12 at 7:10









                                                                  eukras

                                                                  64954




                                                                  64954












                                                                  • Does not work when IN contains more than two e-mail addresses. Please refer to same idea (but fixed) at palindrom's answer
                                                                    – olibre
                                                                    Oct 7 '13 at 13:33












                                                                  • Better use ${IN//;/ } (double slash) to make it also work with more than two values. Beware that any wildcard (*?[) will be expanded. And a trailing empty field will be discarded.
                                                                    – sorontar
                                                                    Oct 26 '16 at 5:14


















                                                                  • Does not work when IN contains more than two e-mail addresses. Please refer to same idea (but fixed) at palindrom's answer
                                                                    – olibre
                                                                    Oct 7 '13 at 13:33












                                                                  • Better use ${IN//;/ } (double slash) to make it also work with more than two values. Beware that any wildcard (*?[) will be expanded. And a trailing empty field will be discarded.
                                                                    – sorontar
                                                                    Oct 26 '16 at 5:14
















                                                                  Does not work when IN contains more than two e-mail addresses. Please refer to same idea (but fixed) at palindrom's answer
                                                                  – olibre
                                                                  Oct 7 '13 at 13:33






                                                                  Does not work when IN contains more than two e-mail addresses. Please refer to same idea (but fixed) at palindrom's answer
                                                                  – olibre
                                                                  Oct 7 '13 at 13:33














                                                                  Better use ${IN//;/ } (double slash) to make it also work with more than two values. Beware that any wildcard (*?[) will be expanded. And a trailing empty field will be discarded.
                                                                  – sorontar
                                                                  Oct 26 '16 at 5:14




                                                                  Better use ${IN//;/ } (double slash) to make it also work with more than two values. Beware that any wildcard (*?[) will be expanded. And a trailing empty field will be discarded.
                                                                  – sorontar
                                                                  Oct 26 '16 at 5:14










                                                                  up vote
                                                                  1
                                                                  down vote













                                                                  Use the set built-in to load up the $@ array:



                                                                  IN="bla@some.com;john@home.com"
                                                                  IFS=';'; set $IN; IFS=$' tn'


                                                                  Then, let the party begin:



                                                                  echo $#
                                                                  for a; do echo $a; done
                                                                  ADDR1=$1 ADDR2=$2





                                                                  share|improve this answer





















                                                                  • Better use set -- $IN to avoid some issues with "$IN" starting with dash. Still, the unquoted expansion of $IN will expand wildcards (*?[).
                                                                    – sorontar
                                                                    Oct 26 '16 at 5:17















                                                                  up vote
                                                                  1
                                                                  down vote













                                                                  Use the set built-in to load up the $@ array:



                                                                  IN="bla@some.com;john@home.com"
                                                                  IFS=';'; set $IN; IFS=$' tn'


                                                                  Then, let the party begin:



                                                                  echo $#
                                                                  for a; do echo $a; done
                                                                  ADDR1=$1 ADDR2=$2





                                                                  share|improve this answer





















                                                                  • Better use set -- $IN to avoid some issues with "$IN" starting with dash. Still, the unquoted expansion of $IN will expand wildcards (*?[).
                                                                    – sorontar
                                                                    Oct 26 '16 at 5:17













                                                                  up vote
                                                                  1
                                                                  down vote










                                                                  up vote
                                                                  1
                                                                  down vote









                                                                  Use the set built-in to load up the $@ array:



                                                                  IN="bla@some.com;john@home.com"
                                                                  IFS=';'; set $IN; IFS=$' tn'


                                                                  Then, let the party begin:



                                                                  echo $#
                                                                  for a; do echo $a; done
                                                                  ADDR1=$1 ADDR2=$2





                                                                  share|improve this answer












                                                                  Use the set built-in to load up the $@ array:



                                                                  IN="bla@some.com;john@home.com"
                                                                  IFS=';'; set $IN; IFS=$' tn'


                                                                  Then, let the party begin:



                                                                  echo $#
                                                                  for a; do echo $a; done
                                                                  ADDR1=$1 ADDR2=$2






                                                                  share|improve this answer












                                                                  share|improve this answer



                                                                  share|improve this answer










                                                                  answered Apr 30 '13 at 3:10









                                                                  jeberle

                                                                  531212




                                                                  531212












                                                                  • Better use set -- $IN to avoid some issues with "$IN" starting with dash. Still, the unquoted expansion of $IN will expand wildcards (*?[).
                                                                    – sorontar
                                                                    Oct 26 '16 at 5:17


















                                                                  • Better use set -- $IN to avoid some issues with "$IN" starting with dash. Still, the unquoted expansion of $IN will expand wildcards (*?[).
                                                                    – sorontar
                                                                    Oct 26 '16 at 5:17
















                                                                  Better use set -- $IN to avoid some issues with "$IN" starting with dash. Still, the unquoted expansion of $IN will expand wildcards (*?[).
                                                                  – sorontar
                                                                  Oct 26 '16 at 5:17




                                                                  Better use set -- $IN to avoid some issues with "$IN" starting with dash. Still, the unquoted expansion of $IN will expand wildcards (*?[).
                                                                  – sorontar
                                                                  Oct 26 '16 at 5:17










                                                                  up vote
                                                                  1
                                                                  down vote













                                                                  Apart from the fantastic answers that were already provided, if it is just a matter of printing out the data you may consider using awk:



                                                                  awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]n", $i)}' <<< "$IN"


                                                                  This sets the field separator to ;, so that it can loop through the fields with a for loop and print accordingly.



                                                                  Test



                                                                  $ IN="bla@some.com;john@home.com"
                                                                  $ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]n", $i)}' <<< "$IN"
                                                                  > [bla@some.com]
                                                                  > [john@home.com]


                                                                  With another input:



                                                                  $ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]n", $i)}' <<< "a;b;c   d;e_;f"
                                                                  > [a]
                                                                  > [b]
                                                                  > [c d]
                                                                  > [e_]
                                                                  > [f]





                                                                  share|improve this answer

























                                                                    up vote
                                                                    1
                                                                    down vote













                                                                    Apart from the fantastic answers that were already provided, if it is just a matter of printing out the data you may consider using awk:



                                                                    awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]n", $i)}' <<< "$IN"


                                                                    This sets the field separator to ;, so that it can loop through the fields with a for loop and print accordingly.



                                                                    Test



                                                                    $ IN="bla@some.com;john@home.com"
                                                                    $ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]n", $i)}' <<< "$IN"
                                                                    > [bla@some.com]
                                                                    > [john@home.com]


                                                                    With another input:



                                                                    $ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]n", $i)}' <<< "a;b;c   d;e_;f"
                                                                    > [a]
                                                                    > [b]
                                                                    > [c d]
                                                                    > [e_]
                                                                    > [f]





                                                                    share|improve this answer























                                                                      up vote
                                                                      1
                                                                      down vote










                                                                      up vote
                                                                      1
                                                                      down vote









                                                                      Apart from the fantastic answers that were already provided, if it is just a matter of printing out the data you may consider using awk:



                                                                      awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]n", $i)}' <<< "$IN"


                                                                      This sets the field separator to ;, so that it can loop through the fields with a for loop and print accordingly.



                                                                      Test



                                                                      $ IN="bla@some.com;john@home.com"
                                                                      $ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]n", $i)}' <<< "$IN"
                                                                      > [bla@some.com]
                                                                      > [john@home.com]


                                                                      With another input:



                                                                      $ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]n", $i)}' <<< "a;b;c   d;e_;f"
                                                                      > [a]
                                                                      > [b]
                                                                      > [c d]
                                                                      > [e_]
                                                                      > [f]





                                                                      share|improve this answer












                                                                      Apart from the fantastic answers that were already provided, if it is just a matter of printing out the data you may consider using awk:



                                                                      awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]n", $i)}' <<< "$IN"


                                                                      This sets the field separator to ;, so that it can loop through the fields with a for loop and print accordingly.



                                                                      Test



                                                                      $ IN="bla@some.com;john@home.com"
                                                                      $ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]n", $i)}' <<< "$IN"
                                                                      > [bla@some.com]
                                                                      > [john@home.com]


                                                                      With another input:



                                                                      $ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]n", $i)}' <<< "a;b;c   d;e_;f"
                                                                      > [a]
                                                                      > [b]
                                                                      > [c d]
                                                                      > [e_]
                                                                      > [f]






                                                                      share|improve this answer












                                                                      share|improve this answer



                                                                      share|improve this answer










                                                                      answered Jan 8 '15 at 10:21









                                                                      fedorqui

                                                                      163k51326371




                                                                      163k51326371






















                                                                          up vote
                                                                          1
                                                                          down vote













                                                                          In Android shell, most of the proposed methods just do not work:



                                                                          $ IFS=':' read -ra ADDR <<<"$PATH"                             
                                                                          /system/bin/sh: can't create temporary file /sqlite_stmt_journals/mksh.EbNoR10629: No such file or directory


                                                                          What does work is:



                                                                          $ for i in ${PATH//:/ }; do echo $i; done
                                                                          /sbin
                                                                          /vendor/bin
                                                                          /system/sbin
                                                                          /system/bin
                                                                          /system/xbin


                                                                          where // means global replacement.






                                                                          share|improve this answer



















                                                                          • 1




                                                                            Fails if any part of $PATH contains spaces (or newlines). Also expands wildcards (asterisk *, question mark ? and braces […]).
                                                                            – sorontar
                                                                            Oct 26 '16 at 5:08















                                                                          up vote
                                                                          1
                                                                          down vote













                                                                          In Android shell, most of the proposed methods just do not work:



                                                                          $ IFS=':' read -ra ADDR <<<"$PATH"                             
                                                                          /system/bin/sh: can't create temporary file /sqlite_stmt_journals/mksh.EbNoR10629: No such file or directory


                                                                          What does work is:



                                                                          $ for i in ${PATH//:/ }; do echo $i; done
                                                                          /sbin
                                                                          /vendor/bin
                                                                          /system/sbin
                                                                          /system/bin
                                                                          /system/xbin


                                                                          where // means global replacement.






                                                                          share|improve this answer



















                                                                          • 1




                                                                            Fails if any part of $PATH contains spaces (or newlines). Also expands wildcards (asterisk *, question mark ? and braces […]).
                                                                            – sorontar
                                                                            Oct 26 '16 at 5:08













                                                                          up vote
                                                                          1
                                                                          down vote










                                                                          up vote
                                                                          1
                                                                          down vote









                                                                          In Android shell, most of the proposed methods just do not work:



                                                                          $ IFS=':' read -ra ADDR <<<"$PATH"                             
                                                                          /system/bin/sh: can't create temporary file /sqlite_stmt_journals/mksh.EbNoR10629: No such file or directory


                                                                          What does work is:



                                                                          $ for i in ${PATH//:/ }; do echo $i; done
                                                                          /sbin
                                                                          /vendor/bin
                                                                          /system/sbin
                                                                          /system/bin
                                                                          /system/xbin


                                                                          where // means global replacement.






                                                                          share|improve this answer














                                                                          In Android shell, most of the proposed methods just do not work:



                                                                          $ IFS=':' read -ra ADDR <<<"$PATH"                             
                                                                          /system/bin/sh: can't create temporary file /sqlite_stmt_journals/mksh.EbNoR10629: No such file or directory


                                                                          What does work is:



                                                                          $ for i in ${PATH//:/ }; do echo $i; done
                                                                          /sbin
                                                                          /vendor/bin
                                                                          /system/sbin
                                                                          /system/bin
                                                                          /system/xbin


                                                                          where // means global replacement.







                                                                          share|improve this answer














                                                                          share|improve this answer



                                                                          share|improve this answer








                                                                          edited Apr 19 '15 at 22:27









                                                                          Peter Mortensen

                                                                          13.3k1983111




                                                                          13.3k1983111










                                                                          answered Feb 20 '15 at 10:49









                                                                          18446744073709551615

                                                                          11.4k16193




                                                                          11.4k16193








                                                                          • 1




                                                                            Fails if any part of $PATH contains spaces (or newlines). Also expands wildcards (asterisk *, question mark ? and braces […]).
                                                                            – sorontar
                                                                            Oct 26 '16 at 5:08














                                                                          • 1




                                                                            Fails if any part of $PATH contains spaces (or newlines). Also expands wildcards (asterisk *, question mark ? and braces […]).
                                                                            – sorontar
                                                                            Oct 26 '16 at 5:08








                                                                          1




                                                                          1




                                                                          Fails if any part of $PATH contains spaces (or newlines). Also expands wildcards (asterisk *, question mark ? and braces […]).
                                                                          – sorontar
                                                                          Oct 26 '16 at 5:08




                                                                          Fails if any part of $PATH contains spaces (or newlines). Also expands wildcards (asterisk *, question mark ? and braces […]).
                                                                          – sorontar
                                                                          Oct 26 '16 at 5:08










                                                                          up vote
                                                                          1
                                                                          down vote













                                                                          Okay guys!



                                                                          Here's my answer!



                                                                          DELIMITER_VAL='='

                                                                          read -d '' F_ABOUT_DISTRO_R <<"EOF"
                                                                          DISTRIB_ID=Ubuntu
                                                                          DISTRIB_RELEASE=14.04
                                                                          DISTRIB_CODENAME=trusty
                                                                          DISTRIB_DESCRIPTION="Ubuntu 14.04.4 LTS"
                                                                          NAME="Ubuntu"
                                                                          VERSION="14.04.4 LTS, Trusty Tahr"
                                                                          ID=ubuntu
                                                                          ID_LIKE=debian
                                                                          PRETTY_NAME="Ubuntu 14.04.4 LTS"
                                                                          VERSION_ID="14.04"
                                                                          HOME_URL="http://www.ubuntu.com/"
                                                                          SUPPORT_URL="http://help.ubuntu.com/"
                                                                          BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
                                                                          EOF

                                                                          SPLIT_NOW=$(awk -F$DELIMITER_VAL '{for(i=1;i<=NF;i++){printf "%sn", $i}}' <<<"${F_ABOUT_DISTRO_R}")
                                                                          while read -r line; do
                                                                          SPLIT+=("$line")
                                                                          done <<< "$SPLIT_NOW"
                                                                          for i in "${SPLIT[@]}"; do
                                                                          echo "$i"
                                                                          done


                                                                          Why this approach is "the best" for me?



                                                                          Because of two reasons:




                                                                          1. You do not need to escape the delimiter;

                                                                          2. You will not have problem with blank spaces. The value will be properly separated in the array!


                                                                          's






                                                                          share|improve this answer























                                                                          • FYI, /etc/os-release and /etc/lsb-release are meant to be sourced, and not parsed. So your method is really wrong. Moreover, you're not quite answering the question about spiltting a string on a delimiter.
                                                                            – gniourf_gniourf
                                                                            Jan 30 '17 at 8:26

















                                                                          up vote
                                                                          1
                                                                          down vote













                                                                          Okay guys!



                                                                          Here's my answer!



                                                                          DELIMITER_VAL='='

                                                                          read -d '' F_ABOUT_DISTRO_R <<"EOF"
                                                                          DISTRIB_ID=Ubuntu
                                                                          DISTRIB_RELEASE=14.04
                                                                          DISTRIB_CODENAME=trusty
                                                                          DISTRIB_DESCRIPTION="Ubuntu 14.04.4 LTS"
                                                                          NAME="Ubuntu"
                                                                          VERSION="14.04.4 LTS, Trusty Tahr"
                                                                          ID=ubuntu
                                                                          ID_LIKE=debian
                                                                          PRETTY_NAME="Ubuntu 14.04.4 LTS"
                                                                          VERSION_ID="14.04"
                                                                          HOME_URL="http://www.ubuntu.com/"
                                                                          SUPPORT_URL="http://help.ubuntu.com/"
                                                                          BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
                                                                          EOF

                                                                          SPLIT_NOW=$(awk -F$DELIMITER_VAL '{for(i=1;i<=NF;i++){printf "%sn", $i}}' <<<"${F_ABOUT_DISTRO_R}")
                                                                          while read -r line; do
                                                                          SPLIT+=("$line")
                                                                          done <<< "$SPLIT_NOW"
                                                                          for i in "${SPLIT[@]}"; do
                                                                          echo "$i"
                                                                          done


                                                                          Why this approach is "the best" for me?



                                                                          Because of two reasons:




                                                                          1. You do not need to escape the delimiter;

                                                                          2. You will not have problem with blank spaces. The value will be properly separated in the array!


                                                                          's






                                                                          share|improve this answer























                                                                          • FYI, /etc/os-release and /etc/lsb-release are meant to be sourced, and not parsed. So your method is really wrong. Moreover, you're not quite answering the question about spiltting a string on a delimiter.
                                                                            – gniourf_gniourf
                                                                            Jan 30 '17 at 8:26















                                                                          up vote
                                                                          1
                                                                          down vote










                                                                          up vote
                                                                          1
                                                                          down vote









                                                                          Okay guys!



                                                                          Here's my answer!



                                                                          DELIMITER_VAL='='

                                                                          read -d '' F_ABOUT_DISTRO_R <<"EOF"
                                                                          DISTRIB_ID=Ubuntu
                                                                          DISTRIB_RELEASE=14.04
                                                                          DISTRIB_CODENAME=trusty
                                                                          DISTRIB_DESCRIPTION="Ubuntu 14.04.4 LTS"
                                                                          NAME="Ubuntu"
                                                                          VERSION="14.04.4 LTS, Trusty Tahr"
                                                                          ID=ubuntu
                                                                          ID_LIKE=debian
                                                                          PRETTY_NAME="Ubuntu 14.04.4 LTS"
                                                                          VERSION_ID="14.04"
                                                                          HOME_URL="http://www.ubuntu.com/"
                                                                          SUPPORT_URL="http://help.ubuntu.com/"
                                                                          BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
                                                                          EOF

                                                                          SPLIT_NOW=$(awk -F$DELIMITER_VAL '{for(i=1;i<=NF;i++){printf "%sn", $i}}' <<<"${F_ABOUT_DISTRO_R}")
                                                                          while read -r line; do
                                                                          SPLIT+=("$line")
                                                                          done <<< "$SPLIT_NOW"
                                                                          for i in "${SPLIT[@]}"; do
                                                                          echo "$i"
                                                                          done


                                                                          Why this approach is "the best" for me?



                                                                          Because of two reasons:




                                                                          1. You do not need to escape the delimiter;

                                                                          2. You will not have problem with blank spaces. The value will be properly separated in the array!


                                                                          's






                                                                          share|improve this answer














                                                                          Okay guys!



                                                                          Here's my answer!



                                                                          DELIMITER_VAL='='

                                                                          read -d '' F_ABOUT_DISTRO_R <<"EOF"
                                                                          DISTRIB_ID=Ubuntu
                                                                          DISTRIB_RELEASE=14.04
                                                                          DISTRIB_CODENAME=trusty
                                                                          DISTRIB_DESCRIPTION="Ubuntu 14.04.4 LTS"
                                                                          NAME="Ubuntu"
                                                                          VERSION="14.04.4 LTS, Trusty Tahr"
                                                                          ID=ubuntu
                                                                          ID_LIKE=debian
                                                                          PRETTY_NAME="Ubuntu 14.04.4 LTS"
                                                                          VERSION_ID="14.04"
                                                                          HOME_URL="http://www.ubuntu.com/"
                                                                          SUPPORT_URL="http://help.ubuntu.com/"
                                                                          BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
                                                                          EOF

                                                                          SPLIT_NOW=$(awk -F$DELIMITER_VAL '{for(i=1;i<=NF;i++){printf "%sn", $i}}' <<<"${F_ABOUT_DISTRO_R}")
                                                                          while read -r line; do
                                                                          SPLIT+=("$line")
                                                                          done <<< "$SPLIT_NOW"
                                                                          for i in "${SPLIT[@]}"; do
                                                                          echo "$i"
                                                                          done


                                                                          Why this approach is "the best" for me?



                                                                          Because of two reasons:




                                                                          1. You do not need to escape the delimiter;

                                                                          2. You will not have problem with blank spaces. The value will be properly separated in the array!


                                                                          's







                                                                          share|improve this answer














                                                                          share|improve this answer



                                                                          share|improve this answer








                                                                          edited Apr 4 '16 at 20:22

























                                                                          answered Apr 4 '16 at 19:54









                                                                          Eduardo Lucio

                                                                          355413




                                                                          355413












                                                                          • FYI, /etc/os-release and /etc/lsb-release are meant to be sourced, and not parsed. So your method is really wrong. Moreover, you're not quite answering the question about spiltting a string on a delimiter.
                                                                            – gniourf_gniourf
                                                                            Jan 30 '17 at 8:26




















                                                                          • FYI, /etc/os-release and /etc/lsb-release are meant to be sourced, and not parsed. So your method is really wrong. Moreover, you're not quite answering the question about spiltting a string on a delimiter.
                                                                            – gniourf_gniourf
                                                                            Jan 30 '17 at 8:26


















                                                                          FYI, /etc/os-release and /etc/lsb-release are meant to be sourced, and not parsed. So your method is really wrong. Moreover, you're not quite answering the question about spiltting a string on a delimiter.
                                                                          – gniourf_gniourf
                                                                          Jan 30 '17 at 8:26






                                                                          FYI, /etc/os-release and /etc/lsb-release are meant to be sourced, and not parsed. So your method is really wrong. Moreover, you're not quite answering the question about spiltting a string on a delimiter.
                                                                          – gniourf_gniourf
                                                                          Jan 30 '17 at 8:26












                                                                          up vote
                                                                          0
                                                                          down vote













                                                                          A one-liner to split a string separated by ';' into an array is:



                                                                          IN="bla@some.com;john@home.com"
                                                                          ADDRS=( $(IFS=";" echo "$IN") )
                                                                          echo ${ADDRS[0]}
                                                                          echo ${ADDRS[1]}


                                                                          This only sets IFS in a subshell, so you don't have to worry about saving and restoring its value.






                                                                          share|improve this answer























                                                                          • -1 this doesn't work here (ubuntu 12.04). it prints only the first echo with all $IN value in it, while the second is empty. you can see it if you put echo "0: "${ADDRS[0]}n echo "1: "${ADDRS[1]} the output is0: bla@some.com;john@home.comn 1: (n is new line)
                                                                            – Luca Borrione
                                                                            Sep 3 '12 at 10:04






                                                                          • 1




                                                                            please refer to nickjb's answer at for a working alternative to this idea stackoverflow.com/a/6583589/1032370
                                                                            – Luca Borrione
                                                                            Sep 3 '12 at 10:05






                                                                          • 1




                                                                            -1, 1. IFS isn't being set in that subshell (it's being passed to the environment of "echo", which is a builtin, so nothing is happening anyway). 2. $IN is quoted so it isn't subject to IFS splitting. 3. The process substitution is split by whitespace, but this may corrupt the original data.
                                                                            – Score_Under
                                                                            Apr 28 '15 at 17:09

















                                                                          up vote
                                                                          0
                                                                          down vote













                                                                          A one-liner to split a string separated by ';' into an array is:



                                                                          IN="bla@some.com;john@home.com"
                                                                          ADDRS=( $(IFS=";" echo "$IN") )
                                                                          echo ${ADDRS[0]}
                                                                          echo ${ADDRS[1]}


                                                                          This only sets IFS in a subshell, so you don't have to worry about saving and restoring its value.






                                                                          share|improve this answer























                                                                          • -1 this doesn't work here (ubuntu 12.04). it prints only the first echo with all $IN value in it, while the second is empty. you can see it if you put echo "0: "${ADDRS[0]}n echo "1: "${ADDRS[1]} the output is0: bla@some.com;john@home.comn 1: (n is new line)
                                                                            – Luca Borrione
                                                                            Sep 3 '12 at 10:04






                                                                          • 1




                                                                            please refer to nickjb's answer at for a working alternative to this idea stackoverflow.com/a/6583589/1032370
                                                                            – Luca Borrione
                                                                            Sep 3 '12 at 10:05






                                                                          • 1




                                                                            -1, 1. IFS isn't being set in that subshell (it's being passed to the environment of "echo", which is a builtin, so nothing is happening anyway). 2. $IN is quoted so it isn't subject to IFS splitting. 3. The process substitution is split by whitespace, but this may corrupt the original data.
                                                                            – Score_Under
                                                                            Apr 28 '15 at 17:09















                                                                          up vote
                                                                          0
                                                                          down vote










                                                                          up vote
                                                                          0
                                                                          down vote









                                                                          A one-liner to split a string separated by ';' into an array is:



                                                                          IN="bla@some.com;john@home.com"
                                                                          ADDRS=( $(IFS=";" echo "$IN") )
                                                                          echo ${ADDRS[0]}
                                                                          echo ${ADDRS[1]}


                                                                          This only sets IFS in a subshell, so you don't have to worry about saving and restoring its value.






                                                                          share|improve this answer














                                                                          A one-liner to split a string separated by ';' into an array is:



                                                                          IN="bla@some.com;john@home.com"
                                                                          ADDRS=( $(IFS=";" echo "$IN") )
                                                                          echo ${ADDRS[0]}
                                                                          echo ${ADDRS[1]}


                                                                          This only sets IFS in a subshell, so you don't have to worry about saving and restoring its value.







                                                                          share|improve this answer














                                                                          share|improve this answer



                                                                          share|improve this answer








                                                                          edited Nov 29 '14 at 22:02









                                                                          Peter Mortensen

                                                                          13.3k1983111




                                                                          13.3k1983111










                                                                          answered Jun 14 '12 at 17:38









                                                                          Michael Hale

                                                                          1,0871215




                                                                          1,0871215












                                                                          • -1 this doesn't work here (ubuntu 12.04). it prints only the first echo with all $IN value in it, while the second is empty. you can see it if you put echo "0: "${ADDRS[0]}n echo "1: "${ADDRS[1]} the output is0: bla@some.com;john@home.comn 1: (n is new line)
                                                                            – Luca Borrione
                                                                            Sep 3 '12 at 10:04






                                                                          • 1




                                                                            please refer to nickjb's answer at for a working alternative to this idea stackoverflow.com/a/6583589/1032370
                                                                            – Luca Borrione
                                                                            Sep 3 '12 at 10:05






                                                                          • 1




                                                                            -1, 1. IFS isn't being set in that subshell (it's being passed to the environment of "echo", which is a builtin, so nothing is happening anyway). 2. $IN is quoted so it isn't subject to IFS splitting. 3. The process substitution is split by whitespace, but this may corrupt the original data.
                                                                            – Score_Under
                                                                            Apr 28 '15 at 17:09




















                                                                          • -1 this doesn't work here (ubuntu 12.04). it prints only the first echo with all $IN value in it, while the second is empty. you can see it if you put echo "0: "${ADDRS[0]}n echo "1: "${ADDRS[1]} the output is0: bla@some.com;john@home.comn 1: (n is new line)
                                                                            – Luca Borrione
                                                                            Sep 3 '12 at 10:04






                                                                          • 1




                                                                            please refer to nickjb's answer at for a working alternative to this idea stackoverflow.com/a/6583589/1032370
                                                                            – Luca Borrione
                                                                            Sep 3 '12 at 10:05






                                                                          • 1




                                                                            -1, 1. IFS isn't being set in that subshell (it's being passed to the environment of "echo", which is a builtin, so nothing is happening anyway). 2. $IN is quoted so it isn't subject to IFS splitting. 3. The process substitution is split by whitespace, but this may corrupt the original data.
                                                                            – Score_Under
                                                                            Apr 28 '15 at 17:09


















                                                                          -1 this doesn't work here (ubuntu 12.04). it prints only the first echo with all $IN value in it, while the second is empty. you can see it if you put echo "0: "${ADDRS[0]}n echo "1: "${ADDRS[1]} the output is0: bla@some.com;john@home.comn 1: (n is new line)
                                                                          – Luca Borrione
                                                                          Sep 3 '12 at 10:04




                                                                          -1 this doesn't work here (ubuntu 12.04). it prints only the first echo with all $IN value in it, while the second is empty. you can see it if you put echo "0: "${ADDRS[0]}n echo "1: "${ADDRS[1]} the output is0: bla@some.com;john@home.comn 1: (n is new line)
                                                                          – Luca Borrione
                                                                          Sep 3 '12 at 10:04




                                                                          1




                                                                          1




                                                                          please refer to nickjb's answer at for a working alternative to this idea stackoverflow.com/a/6583589/1032370
                                                                          – Luca Borrione
                                                                          Sep 3 '12 at 10:05




                                                                          please refer to nickjb's answer at for a working alternative to this idea stackoverflow.com/a/6583589/1032370
                                                                          – Luca Borrione
                                                                          Sep 3 '12 at 10:05




                                                                          1




                                                                          1




                                                                          -1, 1. IFS isn't being set in that subshell (it's being passed to the environment of "echo", which is a builtin, so nothing is happening anyway). 2. $IN is quoted so it isn't subject to IFS splitting. 3. The process substitution is split by whitespace, but this may corrupt the original data.
                                                                          – Score_Under
                                                                          Apr 28 '15 at 17:09






                                                                          -1, 1. IFS isn't being set in that subshell (it's being passed to the environment of "echo", which is a builtin, so nothing is happening anyway). 2. $IN is quoted so it isn't subject to IFS splitting. 3. The process substitution is split by whitespace, but this may corrupt the original data.
                                                                          – Score_Under
                                                                          Apr 28 '15 at 17:09












                                                                          up vote
                                                                          0
                                                                          down vote













                                                                          IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/(){}*? are no problem;simple is beautiful :-)'
                                                                          set -f
                                                                          oldifs="$IFS"
                                                                          IFS=';'; arrayIN=($IN)
                                                                          IFS="$oldifs"
                                                                          for i in "${arrayIN[@]}"; do
                                                                          echo "$i"
                                                                          done
                                                                          set +f


                                                                          Output:



                                                                          bla@some.com
                                                                          john@home.com
                                                                          Charlie Brown <cbrown@acme.com
                                                                          !"#$%&/(){}*? are no problem
                                                                          simple is beautiful :-)


                                                                          Explanation: Simple assignment using parenthesis () converts semicolon separated list into an array provided you have correct IFS while doing that. Standard FOR loop handles individual items in that array as usual.
                                                                          Notice that the list given for IN variable must be "hard" quoted, that is, with single ticks.



                                                                          IFS must be saved and restored since Bash does not treat an assignment the same way as a command. An alternate workaround is to wrap the assignment inside a function and call that function with a modified IFS. In that case separate saving/restoring of IFS is not needed. Thanks for "Bize" for pointing that out.






                                                                          share|improve this answer























                                                                          • !"#$%&/(){}*? are no problem well... not quite: *? are glob characters. So what about creating this directory and file: `mkdir '!"#$%&'; touch '!"#$%&/(){} got you hahahaha - are no problem' and running your command? simple may be beautiful, but when it's broken, it's broken.
                                                                            – gniourf_gniourf
                                                                            Feb 20 '15 at 16:45










                                                                          • @gniourf_gniourf The string is stored in a variable. Please see the original question.
                                                                            – ajaaskel
                                                                            Feb 25 '15 at 7:20








                                                                          • 1




                                                                            @ajaaskel you didn't fully understand my comment. Go in a scratch directory and issue these commands: mkdir '!"#$%&'; touch '!"#$%&/(){} got you hahahaha - are no problem'. They will only create a directory and a file, with weird looking names, I must admit. Then run your commands with the exact IN you gave: IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/(){}*? are no problem;simple is beautiful :-)'. You'll see that you won't get the output you expect. Because you're using a method subject to pathname expansions to split your string.
                                                                            – gniourf_gniourf
                                                                            Feb 25 '15 at 7:26












                                                                          • This is to demonstrate that the characters *, ?, [...] and even, if extglob is set, !(...), @(...), ?(...), +(...) are problems with this method!
                                                                            – gniourf_gniourf
                                                                            Feb 25 '15 at 7:29






                                                                          • 1




                                                                            @gniourf_gniourf Thanks for detailed comments on globbing. I adjusted the code to have globbing off. My point was however just to show that rather simple assignment can do the splitting job.
                                                                            – ajaaskel
                                                                            Feb 26 '15 at 15:26

















                                                                          up vote
                                                                          0
                                                                          down vote













                                                                          IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/(){}*? are no problem;simple is beautiful :-)'
                                                                          set -f
                                                                          oldifs="$IFS"
                                                                          IFS=';'; arrayIN=($IN)
                                                                          IFS="$oldifs"
                                                                          for i in "${arrayIN[@]}"; do
                                                                          echo "$i"
                                                                          done
                                                                          set +f


                                                                          Output:



                                                                          bla@some.com
                                                                          john@home.com
                                                                          Charlie Brown <cbrown@acme.com
                                                                          !"#$%&/(){}*? are no problem
                                                                          simple is beautiful :-)


                                                                          Explanation: Simple assignment using parenthesis () converts semicolon separated list into an array provided you have correct IFS while doing that. Standard FOR loop handles individual items in that array as usual.
                                                                          Notice that the list given for IN variable must be "hard" quoted, that is, with single ticks.



                                                                          IFS must be saved and restored since Bash does not treat an assignment the same way as a command. An alternate workaround is to wrap the assignment inside a function and call that function with a modified IFS. In that case separate saving/restoring of IFS is not needed. Thanks for "Bize" for pointing that out.






                                                                          share|improve this answer























                                                                          • !"#$%&/(){}*? are no problem well... not quite: *? are glob characters. So what about creating this directory and file: `mkdir '!"#$%&'; touch '!"#$%&/(){} got you hahahaha - are no problem' and running your command? simple may be beautiful, but when it's broken, it's broken.
                                                                            – gniourf_gniourf
                                                                            Feb 20 '15 at 16:45










                                                                          • @gniourf_gniourf The string is stored in a variable. Please see the original question.
                                                                            – ajaaskel
                                                                            Feb 25 '15 at 7:20








                                                                          • 1




                                                                            @ajaaskel you didn't fully understand my comment. Go in a scratch directory and issue these commands: mkdir '!"#$%&'; touch '!"#$%&/(){} got you hahahaha - are no problem'. They will only create a directory and a file, with weird looking names, I must admit. Then run your commands with the exact IN you gave: IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/(){}*? are no problem;simple is beautiful :-)'. You'll see that you won't get the output you expect. Because you're using a method subject to pathname expansions to split your string.
                                                                            – gniourf_gniourf
                                                                            Feb 25 '15 at 7:26












                                                                          • This is to demonstrate that the characters *, ?, [...] and even, if extglob is set, !(...), @(...), ?(...), +(...) are problems with this method!
                                                                            – gniourf_gniourf
                                                                            Feb 25 '15 at 7:29






                                                                          • 1




                                                                            @gniourf_gniourf Thanks for detailed comments on globbing. I adjusted the code to have globbing off. My point was however just to show that rather simple assignment can do the splitting job.
                                                                            – ajaaskel
                                                                            Feb 26 '15 at 15:26















                                                                          up vote
                                                                          0
                                                                          down vote










                                                                          up vote
                                                                          0
                                                                          down vote









                                                                          IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/(){}*? are no problem;simple is beautiful :-)'
                                                                          set -f
                                                                          oldifs="$IFS"
                                                                          IFS=';'; arrayIN=($IN)
                                                                          IFS="$oldifs"
                                                                          for i in "${arrayIN[@]}"; do
                                                                          echo "$i"
                                                                          done
                                                                          set +f


                                                                          Output:



                                                                          bla@some.com
                                                                          john@home.com
                                                                          Charlie Brown <cbrown@acme.com
                                                                          !"#$%&/(){}*? are no problem
                                                                          simple is beautiful :-)


                                                                          Explanation: Simple assignment using parenthesis () converts semicolon separated list into an array provided you have correct IFS while doing that. Standard FOR loop handles individual items in that array as usual.
                                                                          Notice that the list given for IN variable must be "hard" quoted, that is, with single ticks.



                                                                          IFS must be saved and restored since Bash does not treat an assignment the same way as a command. An alternate workaround is to wrap the assignment inside a function and call that function with a modified IFS. In that case separate saving/restoring of IFS is not needed. Thanks for "Bize" for pointing that out.






                                                                          share|improve this answer














                                                                          IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/(){}*? are no problem;simple is beautiful :-)'
                                                                          set -f
                                                                          oldifs="$IFS"
                                                                          IFS=';'; arrayIN=($IN)
                                                                          IFS="$oldifs"
                                                                          for i in "${arrayIN[@]}"; do
                                                                          echo "$i"
                                                                          done
                                                                          set +f


                                                                          Output:



                                                                          bla@some.com
                                                                          john@home.com
                                                                          Charlie Brown <cbrown@acme.com
                                                                          !"#$%&/(){}*? are no problem
                                                                          simple is beautiful :-)


                                                                          Explanation: Simple assignment using parenthesis () converts semicolon separated list into an array provided you have correct IFS while doing that. Standard FOR loop handles individual items in that array as usual.
                                                                          Notice that the list given for IN variable must be "hard" quoted, that is, with single ticks.



                                                                          IFS must be saved and restored since Bash does not treat an assignment the same way as a command. An alternate workaround is to wrap the assignment inside a function and call that function with a modified IFS. In that case separate saving/restoring of IFS is not needed. Thanks for "Bize" for pointing that out.







                                                                          share|improve this answer














                                                                          share|improve this answer



                                                                          share|improve this answer








                                                                          edited Apr 19 '15 at 22:28









                                                                          Peter Mortensen

                                                                          13.3k1983111




                                                                          13.3k1983111










                                                                          answered Oct 10 '14 at 11:33









                                                                          ajaaskel

                                                                          961610




                                                                          961610












                                                                          • !"#$%&/(){}*? are no problem well... not quite: *? are glob characters. So what about creating this directory and file: `mkdir '!"#$%&'; touch '!"#$%&/(){} got you hahahaha - are no problem' and running your command? simple may be beautiful, but when it's broken, it's broken.
                                                                            – gniourf_gniourf
                                                                            Feb 20 '15 at 16:45










                                                                          • @gniourf_gniourf The string is stored in a variable. Please see the original question.
                                                                            – ajaaskel
                                                                            Feb 25 '15 at 7:20








                                                                          • 1




                                                                            @ajaaskel you didn't fully understand my comment. Go in a scratch directory and issue these commands: mkdir '!"#$%&'; touch '!"#$%&/(){} got you hahahaha - are no problem'. They will only create a directory and a file, with weird looking names, I must admit. Then run your commands with the exact IN you gave: IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/(){}*? are no problem;simple is beautiful :-)'. You'll see that you won't get the output you expect. Because you're using a method subject to pathname expansions to split your string.
                                                                            – gniourf_gniourf
                                                                            Feb 25 '15 at 7:26












                                                                          • This is to demonstrate that the characters *, ?, [...] and even, if extglob is set, !(...), @(...), ?(...), +(...) are problems with this method!
                                                                            – gniourf_gniourf
                                                                            Feb 25 '15 at 7:29






                                                                          • 1




                                                                            @gniourf_gniourf Thanks for detailed comments on globbing. I adjusted the code to have globbing off. My point was however just to show that rather simple assignment can do the splitting job.
                                                                            – ajaaskel
                                                                            Feb 26 '15 at 15:26




















                                                                          • !"#$%&/(){}*? are no problem well... not quite: *? are glob characters. So what about creating this directory and file: `mkdir '!"#$%&'; touch '!"#$%&/(){} got you hahahaha - are no problem' and running your command? simple may be beautiful, but when it's broken, it's broken.
                                                                            – gniourf_gniourf
                                                                            Feb 20 '15 at 16:45










                                                                          • @gniourf_gniourf The string is stored in a variable. Please see the original question.
                                                                            – ajaaskel
                                                                            Feb 25 '15 at 7:20








                                                                          • 1




                                                                            @ajaaskel you didn't fully understand my comment. Go in a scratch directory and issue these commands: mkdir '!"#$%&'; touch '!"#$%&/(){} got you hahahaha - are no problem'. They will only create a directory and a file, with weird looking names, I must admit. Then run your commands with the exact IN you gave: IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/(){}*? are no problem;simple is beautiful :-)'. You'll see that you won't get the output you expect. Because you're using a method subject to pathname expansions to split your string.
                                                                            – gniourf_gniourf
                                                                            Feb 25 '15 at 7:26












                                                                          • This is to demonstrate that the characters *, ?, [...] and even, if extglob is set, !(...), @(...), ?(...), +(...) are problems with this method!
                                                                            – gniourf_gniourf
                                                                            Feb 25 '15 at 7:29






                                                                          • 1




                                                                            @gniourf_gniourf Thanks for detailed comments on globbing. I adjusted the code to have globbing off. My point was however just to show that rather simple assignment can do the splitting job.
                                                                            – ajaaskel
                                                                            Feb 26 '15 at 15:26


















                                                                          !"#$%&/(){}*? are no problem well... not quite: *? are glob characters. So what about creating this directory and file: `mkdir '!"#$%&'; touch '!"#$%&/(){} got you hahahaha - are no problem' and running your command? simple may be beautiful, but when it's broken, it's broken.
                                                                          – gniourf_gniourf
                                                                          Feb 20 '15 at 16:45




                                                                          !"#$%&/(){}*? are no problem well... not quite: *? are glob characters. So what about creating this directory and file: `mkdir '!"#$%&'; touch '!"#$%&/(){} got you hahahaha - are no problem' and running your command? simple may be beautiful, but when it's broken, it's broken.
                                                                          – gniourf_gniourf
                                                                          Feb 20 '15 at 16:45












                                                                          @gniourf_gniourf The string is stored in a variable. Please see the original question.
                                                                          – ajaaskel
                                                                          Feb 25 '15 at 7:20






                                                                          @gniourf_gniourf The string is stored in a variable. Please see the original question.
                                                                          – ajaaskel
                                                                          Feb 25 '15 at 7:20






                                                                          1




                                                                          1




                                                                          @ajaaskel you didn't fully understand my comment. Go in a scratch directory and issue these commands: mkdir '!"#$%&'; touch '!"#$%&/(){} got you hahahaha - are no problem'. They will only create a directory and a file, with weird looking names, I must admit. Then run your commands with the exact IN you gave: IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/(){}*? are no problem;simple is beautiful :-)'. You'll see that you won't get the output you expect. Because you're using a method subject to pathname expansions to split your string.
                                                                          – gniourf_gniourf
                                                                          Feb 25 '15 at 7:26






                                                                          @ajaaskel you didn't fully understand my comment. Go in a scratch directory and issue these commands: mkdir '!"#$%&'; touch '!"#$%&/(){} got you hahahaha - are no problem'. They will only create a directory and a file, with weird looking names, I must admit. Then run your commands with the exact IN you gave: IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/(){}*? are no problem;simple is beautiful :-)'. You'll see that you won't get the output you expect. Because you're using a method subject to pathname expansions to split your string.
                                                                          – gniourf_gniourf
                                                                          Feb 25 '15 at 7:26














                                                                          This is to demonstrate that the characters *, ?, [...] and even, if extglob is set, !(...), @(...), ?(...), +(...) are problems with this method!
                                                                          – gniourf_gniourf
                                                                          Feb 25 '15 at 7:29




                                                                          This is to demonstrate that the characters *, ?, [...] and even, if extglob is set, !(...), @(...), ?(...), +(...) are problems with this method!
                                                                          – gniourf_gniourf
                                                                          Feb 25 '15 at 7:29




                                                                          1




                                                                          1




                                                                          @gniourf_gniourf Thanks for detailed comments on globbing. I adjusted the code to have globbing off. My point was however just to show that rather simple assignment can do the splitting job.
                                                                          – ajaaskel
                                                                          Feb 26 '15 at 15:26






                                                                          @gniourf_gniourf Thanks for detailed comments on globbing. I adjusted the code to have globbing off. My point was however just to show that rather simple assignment can do the splitting job.
                                                                          – ajaaskel
                                                                          Feb 26 '15 at 15:26












                                                                          up vote
                                                                          0
                                                                          down vote













                                                                          Maybe not the most elegant solution, but works with * and spaces:



                                                                          IN="bla@so me.com;*;john@home.com"
                                                                          for i in `delims=${IN//[^;]}; seq 1 $((${#delims} + 1))`
                                                                          do
                                                                          echo "> [`echo $IN | cut -d';' -f$i`]"
                                                                          done


                                                                          Outputs



                                                                          > [bla@so me.com]
                                                                          > [*]
                                                                          > [john@home.com]


                                                                          Other example (delimiters at beginning and end):



                                                                          IN=";bla@so me.com;*;john@home.com;"
                                                                          >
                                                                          > [bla@so me.com]
                                                                          > [*]
                                                                          > [john@home.com]
                                                                          >


                                                                          Basically it removes every character other than ; making delims eg. ;;;. Then it does for loop from 1 to number-of-delimiters as counted by ${#delims}. The final step is to safely get the $ith part using cut.






                                                                          share|improve this answer

























                                                                            up vote
                                                                            0
                                                                            down vote













                                                                            Maybe not the most elegant solution, but works with * and spaces:



                                                                            IN="bla@so me.com;*;john@home.com"
                                                                            for i in `delims=${IN//[^;]}; seq 1 $((${#delims} + 1))`
                                                                            do
                                                                            echo "> [`echo $IN | cut -d';' -f$i`]"
                                                                            done


                                                                            Outputs



                                                                            > [bla@so me.com]
                                                                            > [*]
                                                                            > [john@home.com]


                                                                            Other example (delimiters at beginning and end):



                                                                            IN=";bla@so me.com;*;john@home.com;"
                                                                            >
                                                                            > [bla@so me.com]
                                                                            > [*]
                                                                            > [john@home.com]
                                                                            >


                                                                            Basically it removes every character other than ; making delims eg. ;;;. Then it does for loop from 1 to number-of-delimiters as counted by ${#delims}. The final step is to safely get the $ith part using cut.






                                                                            share|improve this answer























                                                                              up vote
                                                                              0
                                                                              down vote










                                                                              up vote
                                                                              0
                                                                              down vote









                                                                              Maybe not the most elegant solution, but works with * and spaces:



                                                                              IN="bla@so me.com;*;john@home.com"
                                                                              for i in `delims=${IN//[^;]}; seq 1 $((${#delims} + 1))`
                                                                              do
                                                                              echo "> [`echo $IN | cut -d';' -f$i`]"
                                                                              done


                                                                              Outputs



                                                                              > [bla@so me.com]
                                                                              > [*]
                                                                              > [john@home.com]


                                                                              Other example (delimiters at beginning and end):



                                                                              IN=";bla@so me.com;*;john@home.com;"
                                                                              >
                                                                              > [bla@so me.com]
                                                                              > [*]
                                                                              > [john@home.com]
                                                                              >


                                                                              Basically it removes every character other than ; making delims eg. ;;;. Then it does for loop from 1 to number-of-delimiters as counted by ${#delims}. The final step is to safely get the $ith part using cut.






                                                                              share|improve this answer












                                                                              Maybe not the most elegant solution, but works with * and spaces:



                                                                              IN="bla@so me.com;*;john@home.com"
                                                                              for i in `delims=${IN//[^;]}; seq 1 $((${#delims} + 1))`
                                                                              do
                                                                              echo "> [`echo $IN | cut -d';' -f$i`]"
                                                                              done


                                                                              Outputs



                                                                              > [bla@so me.com]
                                                                              > [*]
                                                                              > [john@home.com]


                                                                              Other example (delimiters at beginning and end):



                                                                              IN=";bla@so me.com;*;john@home.com;"
                                                                              >
                                                                              > [bla@so me.com]
                                                                              > [*]
                                                                              > [john@home.com]
                                                                              >


                                                                              Basically it removes every character other than ; making delims eg. ;;;. Then it does for loop from 1 to number-of-delimiters as counted by ${#delims}. The final step is to safely get the $ith part using cut.







                                                                              share|improve this answer












                                                                              share|improve this answer



                                                                              share|improve this answer










                                                                              answered Feb 26 '16 at 12:20









                                                                              Petr Újezdský

                                                                              409310




                                                                              409310






















                                                                                  1 2
                                                                                  next




                                                                                  protected by Jorgesys Dec 19 '13 at 21:39



                                                                                  Thank you for your interest in this question.
                                                                                  Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



                                                                                  Would you like to answer one of these unanswered questions instead?



                                                                                  Popular posts from this blog

                                                                                  Schultheiß

                                                                                  Android Play Services Check

                                                                                  Where to put API Key in Google Cloud Vision for PHP