80

I have a string in the next format

id;some text here with possible ; inside

and want to split it to 2 strings by first occurrence of the ;. So, it should be: id and some text here with possible ; inside

I know how to split the string (for instance, with cut -d ';' -f1), but it will split to more parts since I have ; inside the left part.

3

5 Answers 5

100

cut sounds like a suitable tool for this:

bash-4.2$ s='id;some text here with possible ; inside'

bash-4.2$ id="$( cut -d ';' -f 1 <<< "$s" )"; echo "$id"
id

bash-4.2$ string="$( cut -d ';' -f 2- <<< "$s" )"; echo "$string"
some text here with possible ; inside

But read is even more suitable:

bash-4.2$ IFS=';' read -r id string <<< "$s"

bash-4.2$ echo "$id"
id

bash-4.2$ echo "$string"
some text here with possible ; inside
9
  • 3
    Great! It works like a charm! I will select the read since i'm using bash. Thank you @manatwork!
    – gakhov
    Oct 30, 2012 at 13:45
  • The cut approach will only work when "$s" doesn't contain newline characters. read is in any Bourne-like shell. <<< is in rc, zsh and recent versions of bash and ksh93 and is the one that is not standard. Oct 30, 2012 at 14:24
  • Oops, you are right @StephaneChazelas. My mind was at -a for some reason when mentioning bash's read. (Evidently of no use here.)
    – manatwork
    Oct 30, 2012 at 14:34
  • I forgot to mention that the read approach doesn't work if $s contains newline characters either. I've added my own answer. Oct 30, 2012 at 14:37
  • 1
    I would like to emphasize the trailing dash in -f 2- in the string="$( cut -d ';' -f 2- <<< "$s" )"; echo "$string" command. This is what ignores the rest of the delimiters in the string for the printout. Not obvious when looking at the man page of cut
    – Steen
    Jun 27, 2014 at 8:14
23

With any standard sh (including bash):

sep=';'
case $s in
  (*"$sep"*)
    before=${s%%"$sep"*}
    after=${s#*"$sep"}
    ;;
  (*)
    before=$s
    after=
    ;;
esac

read based solutions would work for single character (and with some shells, single-byte) values of $sep other than space, tab or newline and only if $s doesn't contain newline characters.

cut based solutions would only work if $s doesn't contain newline characters.

sed solutions could be devised that handle all the corner cases with any value of $sep, but it's not worth going that far when there's builtin support in the shell for that.

8

As you have mentioned that you want to assign the values to id and string

first assign your pattern to a variable(say str)

    str='id;some text here with possible ; inside'
    id=${str%%;} 
    string=${str#;}

Now you have your values in respective variables

3
  • if you are getting your pattern from a command then use set -- some_command ,then your pattern will get stored in $1 and use the above code with 1 instead of str Oct 31, 2012 at 12:43
  • 1
    How is this answer different from @StephaneChazelas?
    – Bernhard
    Oct 31, 2012 at 12:50
  • 4
    Should be ${str%%;*} for id and ${str#*;} for str (with the asterisks). This is an old answer though so perhaps this worked on older versions of bash, but these changes were required for me on bash 4.2+ (and possibly earlier, I did not test).
    – fquinner
    Dec 9, 2020 at 12:48
8

Solution in standard bash:

    text='id;some text here with possible ; inside'
    text2=${text#*;}
    text1=${text%"$text2"}

    echo $text1
    #=> id;
    echo $text2
    #=> some text here with possible ; insideDD
1
  • Amazing thanks! Best answer. Although you need to do text1=${text%";$text2"} to remove the trailing ; in $1text
    – pez
    Mar 17, 2020 at 19:38
5

In addition to the other solutions, you could try something regex based:

a="$(sed 's/;.*//' <<< "$s")"
b="$(sed 's/^[^;]*;//' <<< "$s")"

or depending on what you are trying to do exactly, you could use

sed -r 's/^([^;]*);(.*)/\1 ADD THIS TEXT BETWEEN YOUR STRINGS \2/'

where \1 and \2 contain the two substrings you were wanting.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.