How can I join elements of an array in Bash?

前端 未结 30 2154
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-22 12:05

If I have an array like this in Bash:

FOO=( a b c )

How do I join the elements with commas? For example, producing a,b,c.

相关标签:
30条回答
  • 2020-11-22 12:18

    Perhaps late for the party, but this works for me:

    function joinArray() {
      local delimiter="${1}"
      local output="${2}"
      for param in ${@:3}; do
        output="${output}${delimiter}${param}"
      done
    
      echo "${output}"
    }
    
    0 讨论(0)
  • 2020-11-22 12:20

    Combine best of all worlds so far with following idea.

    # join with separator
    join_ws()  { local IFS=; local s="${*/#/$1}"; echo "${s#"$1$1$1"}"; }
    

    This little masterpiece is

    • 100% pure bash ( parameter expansion with IFS temporarily unset, no external calls, no printf ... )
    • compact, complete and flawless ( works with single- and multi-character limiters, works with limiters containing white space, line breaks and other shell special characters, works with empty delimiter )
    • efficient ( no subshell, no array copy )
    • simple and stupid and, to a certain degree, beautiful and instructive as well

    Examples:

    $ join_ws , a b c
    a,b,c
    $ join_ws '' a b c
    abc
    $ join_ws $'\n' a b c
    a
    b
    c
    $ join_ws ' \/ ' A B C
    A \/ B \/ C
    
    0 讨论(0)
  • 2020-11-22 12:20

    Many, if not most, of these solutions rely on arcane syntax, brain-busting regex tricks, or calls to external executables. I would like to propose a simple, bash-only solution that is very easy to understand, and only slightly sub-optimal, performance-wise.

    join_by () {
        # Argument #1 is the separator. It can be multi-character.
        # Argument #2, 3, and so on, are the elements to be joined.
        # Usage: join_by ", " "${array[@]}"
        local SEPARATOR="$1"
        shift
    
        local F=0
        for x in "$@"
        do
            if [[ F -eq 1 ]]
            then
                echo -n "$SEPARATOR"
            else
                F=1
            fi
            echo -n "$x"
        done
        echo
    }
    

    Example:

    $ a=( 1 "2 2" 3 )
    $ join_by ", " "${a[@]}"
    1, 2 2, 3
    $ 
    

    I'd like to point out that any solution that uses /usr/bin/[ or /usr/bin/printf is inherently slower than my solution, since I use 100% pure bash. As an example of its performance, Here's a demo where I create an array with 1,000,000 random integers, then join them all with a comma, and time it.

    $ eval $(echo -n "a=("; x=0 ; while [[ x -lt 1000000 ]]; do echo -n " $RANDOM" ; x=$((x+1)); done; echo " )")
    $ time join_by , ${a[@]} >/dev/null
    real    0m8.590s
    user    0m8.591s
    sys     0m0.000s
    $ 
    
    0 讨论(0)
  • 2020-11-22 12:23

    A 100% pure Bash function that supports multi-character delimiters is:

    function join_by { local d=$1; shift; local f=$1; shift; printf %s "$f" "${@/#/$d}"; }
    

    For example,

    join_by , a b c #a,b,c
    join_by ' , ' a b c #a , b , c
    join_by ')|(' a b c #a)|(b)|(c
    join_by ' %s ' a b c #a %s b %s c
    join_by $'\n' a b c #a<newline>b<newline>c
    join_by - a b c #a-b-c
    join_by '\' a b c #a\b\c
    join_by '-n' '-e' '-E' '-n' #-e-n-E-n-n
    join_by , #
    join_by , a #a
    

    The code above is based on the ideas by @gniourf_gniourf, @AdamKatz, and @MattCowell.

    Alternatively, a simpler function that supports only single character delimiter, would be:

    function join_by { local IFS="$1"; shift; echo "$*"; }
    

    For example,

    join_by , a "b c" d #a,b c,d
    join_by / var local tmp #var/local/tmp
    join_by , "${FOO[@]}" #a,b,c
    

    This solution is based on Pascal Pilz's original suggestion.

    0 讨论(0)
  • 2020-11-22 12:23
    s=$(IFS=, eval 'echo "${FOO[*]}"')
    
    0 讨论(0)
  • 2020-11-22 12:25

    In case the elements you want to join is not an array just a space separated string, you can do something like this:

    foo="aa bb cc dd"
    bar=`for i in $foo; do printf ",'%s'" $i; done`
    bar=${bar:1}
    echo $bar
        'aa','bb','cc','dd'
    

    for example, my use case is that some strings are passed in my shell script and I need to use this to run on a SQL query:

    ./my_script "aa bb cc dd"
    

    In my_script, I need to do "SELECT * FROM table WHERE name IN ('aa','bb','cc','dd'). Then above command will be useful.

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