How can I join elements of an array in Bash?

Solution 1:

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

function join_by {
  local d=${1-} f=${2-}
  if shift 2; then
    printf %s "$f" "${@/#/$d}"
  fi
}

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, @MattCowell, and @x-yuri. It works with options errexit (set -e) and nounset (set -u).

Alternatively, a simpler function that supports only a 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.

A detailed explanation of the solutions previously proposed here can be found in "How to join() array elements in a bash script", an article by meleu at dev.to.

Solution 2:

Yet another solution:

#!/bin/bash
foo=('foo bar' 'foo baz' 'bar baz')
bar=$(printf ",%s" "${foo[@]}")
bar=${bar:1}

echo $bar

Edit: same but for multi-character variable length separator:

#!/bin/bash
separator=")|(" # e.g. constructing regex, pray it does not contain %s
foo=('foo bar' 'foo baz' 'bar baz')
regex="$( printf "${separator}%s" "${foo[@]}" )"
regex="${regex:${#separator}}" # remove leading separator
echo "${regex}"
# Prints: foo bar)|(foo baz)|(bar baz

Solution 3:

$ foo=(a "b c" d)
$ bar=$(IFS=, ; echo "${foo[*]}")
$ echo "$bar"
a,b c,d

Solution 4:

Maybe, e.g.,

SAVE_IFS="$IFS"
IFS=","
FOOJOIN="${FOO[*]}"
IFS="$SAVE_IFS"

echo "$FOOJOIN"

Solution 5:

Surprisingly my solution is not yet given :) This is the simplest way for me. It doesn't need a function:

IFS=, eval 'joined="${foo[*]}"'

Note: This solution was observed to work well in non-POSIX mode. In POSIX mode, the elements are still joined properly, but IFS=, becomes permanent.