maneira unix portátil de juntar strings com separador

4

Existe uma maneira portável de unix shellscripting de juntar um número de strings junto com um determinado separador, da seguinte forma:

$ strjoin --- foo bar baz quux
foo---bar---baz---quux

Claro que eu poderia usar um $ scripting_language em um liner ou um loop explícito e feio em uma função de shellscript, mas os hackers unix do antigo provavelmente também precisavam disso, então alguém fez um comando padrão como esse que eu don ' Não sei sobre algum lugar no passado, certo?

editar

O método sed é certamente o mais fácil em muitas situações, mas não funciona se as strings puderem conter espaços. E muitas das outras respostas também não lidam com isso. Existe alguma solução diferente do truque $IFS que manipula espaços (e todos os caracteres possíveis em geral) e não requer a gravação de um loop completo?

    
por JanKanis 15.09.2011 / 19:04

6 respostas

4

Para um separador longo de vários caracteres, você pode usar:

  • sed (como já foi apontado por @Mark )

    $ echo foo bar baz quux | sed "s/ /---/g"
    
  • ex

    $ echo foo bar baz quux | ex +"s/ /---/gp" -cq! /dev/stdin
    $ ex +"s/ /---/gp" -scq! <(echo foo bar baz quux)
    
  • printf (mas mostrará o separador de término extra)

    $ printf "%s---" foo bar baz quux
    
  • usando a seguinte função do shell (de acordo com esta postagem do SO ):

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

    Uso:

    $ join_by '---' foo bar baz quux
    

Para separadores longos de um caractere, você pode usar:

  • tr

    echo foo bar baz quux | tr ' ' '-'
    
por 22.12.2016 / 18:13
1

Perl não é esse complexo para operações simples:

$ perl -e 's/ /---/g'
    
por 15.09.2011 / 21:17
0

Além do comentário do @embobo (que, esperamos, chegará a uma resposta em breve), o perl pode ser usado para dividir e juntar seqüências arbitrárias. Isso é mais complexo do que usar sed e, com base no exemplo acima, seria um grande exagero.

    
por 15.09.2011 / 20:48
0

awk versão:

function join(a, start, end, sep, result, i) {
    sep = sep ? sep : " "
    start = start ? start : 1
    end = end ? end : sizeof(a)
    if (sep == SUBSEP) # magic value
       sep = ""
    result = a[start]
    for (i = start + 1; i <= end; i++)
        result = result sep a[i]
    return result
}

Chame-o com gawk com --source suas sequências:

$ gawk -f join.awk --source 'BEGIN { split("foo bar quux",a); print join(a,1,3,"---") }'
foo---bar---quux

Versão do script da shell:

function join() {
    for i in "$@"; do
        echo -n "$i""---"
    done
    echo
}

join foo bar baz quux 

Chame e apare o último separador:

$ ./join.sh | sed 's/\-\-\-$//'
foo---bar---baz---quux
    
por 15.09.2011 / 20:54
0

lam

Aqui está o exemplo usando o comando lam :

$ SEP="---"; lam <(echo foo) -s$SEP <(echo bar) -s$SEP <(echo baz) -s$SEP <(echo quux)
foo---bar---baz---quux

paste

Se o separador tiver um caractere, o comando paste poderá ser usado:

$ printf "%s\n" foo bar baz quux | paste -sd-
foo-bar-baz-quux
    
por 21.06.2018 / 00:55
0

O melhor método que encontrei é o loop explícito e feio que você mencionou.

join(){
    # If no arguments, do nothing.
    # This avoids confusing errors in some shells.
    if [ $# -eq 0 ]; then
        return
    fi

    local joiner="$1"
    shift

    while [ $# -gt 1 ]; do
        printf "%s%s" "$1" "$joiner"
        shift
    done

    printf '%s\n' "$1"
}

Uso:

$ join --- foo bar baz quux
foo---bar---baz---quux

Testado com Bash, Dash e Zsh no Ubuntu, e deve funcionar em outros shells baseados em Bourne.

    
por 22.10.2018 / 02:28