Eu estava precisando juntar os elementos do array em uma só string usando um | como separador.

Em linguagens como JavaScript e PHP isso é obtido através de funções/métodos nativos, tipo join() ou implode(). Em bash teremos que implementar nós mesmos.

Uma rápida googlada me levou a uma solução bem simples e bacana. Mostro aqui a minha versão:

joinBy() {
    local IFS="$1"
    echo "${*:2}"
}

Agora vamos ver esse código em ação:

$ . joinBy.sh
$ joinBy , zacarias mussum 'didi mocó' 'dedé santana'
zacarias,mussum,didi mocó,dedé santana
$ joinBy | zacarias mussum 'didi mocó' 'dedé santana'
zacarias: command not found
$ # Ooops! Precisamos proteger o pipe com 'aspas'
$ joinBy '|' zacarias mussum 'didi mocó' 'dedé santana'
zacarias|mussum|didi mocó|dedé santana

Explicando

Checando a manpage do bash, na seção de "Special Parameters", conseguimos ver a resposta para isso. Lá vemos a explicação do * asterisco e do @ arroba no contexto de parâmetros da linha de comando ($1, $2, etc.), mas a mesma lógica se aplica a expansão de arrays.

Este é um trecho da descrição da expansão feita com * asterisco (tradução livre feita por mim):

Quando a expansão ocorre entre aspas duplas, expande para uma única palavra com o valor de cada parâmetro separado pelo primeiro caractere da variável especial IFS. Isto é, "$*" é equivalente a "$1c$2c...", onde c é o primeiro caractere da variável IFS.

E a seguir um trecho da descrição da expansão feita com @ arroba:

Quando a expansão ocorre entre aspas duplas, cada parâmetro expande para uma palavra separada [por um espaço]. Isto é "$@" é equivalente a "$1" "$2" ...

Resumo:

  • @ arroba: expande separando com um espaço.
  • * asterisco: expande separando com o primeiro caractere do IFS.

Devido a esta propriedade, se tentarmos a função joinBy() usando @ arroba no lugar de * asterisco (echo "${@:2}"), não obteremos o resultado desejado.

Fontes