BASH: Split a string without ‘cut’ or ‘awk’

For a little test script I'm writing I needed to split a line on a ';' but preservere the "s and 's, something that echo doesn't like to do. Digging deeper into the bash docs I see that there are some handy string handling functions.

#!/bin/bash
line='this "is" a command;this "is" a pattern'
COMMAND=${line%;*}
PATTERN=${line#*;}
echo $COMMAND
echo $PATTERN

And the output would be:

this "is" a command
this "is" a pattern

34 thoughts on “BASH: Split a string without ‘cut’ or ‘awk’

  1. @nihilist:
    If you have multiple separator characters, like this:

    string1;string2;string3

    then you can split it this way:

    original=’string1;string2;string3′
    part1=${original%%;*}; rest=${original#*;}
    part2=${rest%%;*}; rest=${rest#*;}
    part3=${rest%%;*};

    This should work for arbitrary number of parts.

  2. very nice … thanks

    How to do if I have 3 tags (or more) like

    line=’this “is” a command;this “is” a pattern;this “is” a bla’
    COMMAND=${line%;*}
    PATTERN=${line#*;}
    echo $COMMAND
    echo $PATTERN

  3. @oli:

    I’d just use ‘cut -d”;” -f1’ (and 2 and 3) to get each element then.
    COMMAND=$(echo $line | cut -d”;” -f1)
    PATTERN=$(echo $line | cut -d”;” -f2)
    BLAH=$(echo $line | cut -d”;” -f3)

    I am sure there is a way to split it properly, but I don’t recall how.

  4. Thanks for the way here.
    And I would like to share the way for 3 tag line, I tested this and used it.

    COMMAND=${line%;*;*}
    PATTERN=${line#*;}
    PATTERN=${PATTERN%;*}
    BLAH=${line#*;*;}

  5. Pingback: et lux in tenebris lucet

  6. If I am right, this just works if you know how much delimiter are in the string you wish to split. Nice would be if this should work without knowing this…

    cheers — jerik

  7. You sir are Awesome! Not that this makes me enjoy bash any more(I prefer real programming languages), but this is much more understandable than that sed/awk stuff.

    Bookmarked, Stumbled, Saved.

  8. #!/bin/bash
    # Split the command line argument on the colon character.

    IFS=”:”; declare -a Array=($*)

    echo “Array[0]=${Array[0]}”
    echo “Array[1]=${Array[1]}”
    echo “Array[2]=${Array[2]}”
    echo “Array[3]=${Array[3]}”

  9. Hi,

    redefinig IFS did work only on Linux, not on Solaris. So I wrote
    a loop to split the input data into an array.

    #!/bin/bash
    declare -a Array

    original=’string1 with spaces ~string2~string3~;; special chars \;~last thing’
    rest=$original
    i=0

    #create Array from line separated by ~
    while true; do
    restTmp=$rest
    part1=${rest%%~*}; rest=${rest#*~}
    Array[$i]=”$part1″
    #echo $rest
    i=`expr $i + 1`
    if [ “$rest” == “$restTmp” ]; then
    break
    fi
    done

    #access Array
    echo “Array[0]=${Array[0]}”
    echo “Array[1]=${Array[1]}”
    echo “Array[2]=${Array[2]}”
    echo “Array[3]=${Array[3]}”
    echo “Array[4]=${Array[4]}”

    br

    Harald Strack

  10. # Using your original example I derived a way to loop thru a tokenized string:

    #!/bin/bash
    STR=”a,b,cc,ddd,ee,f,gg”
    TOKEN=””

    echo STR: $STR
    echo “Tokens:”

    until [ “$STR” == “$TOKEN” ]; do
    TOKEN=${STR%%,*}
    STR=${STR#*,}
    echo $TOKEN
    done

  11. I’m not sure if I understand the problem, however this will split the lines regardless of how many items:

    ‘echo $line | cut -d’;’ -f1- –output-delimiter=$’n”

    ‘-f1-‘ will print all items starting with the first one. Notice the dash after f1.

    ### Output ###
    this “is” a command
    this “is” a pattern

Leave a Reply

Your email address will not be published. Required fields are marked *