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

后端 未结 30 1686
萌比男神i
萌比男神i 2020-11-21 04:58

I have this string stored in a variable:

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

Now I would like to split the strings by ; delimite

相关标签:
30条回答
  • 2020-11-21 05:40

    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.

    0 讨论(0)
  • 2020-11-21 05:41

    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 "$@"
    
    0 讨论(0)
  • 2020-11-21 05:41

    you can apply awk to many situations

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

    also you can use this

    echo "bla@some.com;john@home.com"|awk -F';' '{print $1,$2}' OFS="\n"
    
    0 讨论(0)
  • 2020-11-21 05:42

    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)
    
    0 讨论(0)
  • 2020-11-21 05:43

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

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

    Look:

    $ in=$'one;two three;*;there is\na newline\nin this field'
    $ IFS=';' read -d '' -ra array < <(printf '%s;\0' "$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;\0' "$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")
    
    0 讨论(0)
  • 2020-11-21 05:43

    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.

    0 讨论(0)
提交回复
热议问题