Remove a última vírgula de um bash para uma string gerada por loop

5

Estou lidando com uma situação em que preciso criar uma lista separada por vírgulas de uma matriz em um heredoc e remover a última vírgula. Eu estou usando o bash for canalizado para sed , que está apagando todas as vírgulas ao invés do último. Um exemplo simplificado é o seguinte:

x=$(for i in a b c; do echo "${i}",; done| sed 's/,$//')
echo $x
a b c

Saída desejada:

a, b, c

Qualquer sugestão apreciada.

    
por Ketan 29.04.2014 / 22:41

7 respostas

6

O problema era que, por padrão, echo adicionava uma nova linha toda vez que era chamada e sed estava operando nessas novas linhas. Você não podia ver isso porque, quando o bash processa $(...) , essas novas linhas são convertidas em espaços. Assim, para corrigir o problema ao fazer a menor alteração na sua abordagem:

$ x=$(for i in a b c; do echo -n "${i}",; done| sed 's/,$//') ; echo $x
a,b,c

A opção -n diz echo para não adicionar novas linhas.

Se você deseja espaços entre os itens, eles são facilmente adicionados:

$ x=$(for i in a b c; do echo -n "${i}, " ; done| sed 's/, $//') ;echo $x
a, b, c
    
por 29.04.2014 / 22:46
7

Uma opção é ficar com bash

arr=(a b c)
x=$(IFS=,;printf  "%s" "${arr[*]}")
echo "$x"
a,b,c

Alternadamente

arr=(a b c)
printf -v x "%s," "${arr[@]}"
x=${x%,}
echo "$x"
a,b,c

Com a segunda opção, você pode definir o separador como , (vírgula seguida de espaço) em vez de , sozinho

printf -v x "%s, " "${arr[@]}"
x=${x%, }
echo "$x"
a, b, c
    
por 29.04.2014 / 22:50
3

outra técnica útil para isso é paste -s :

$ arr=(a b c)
$ printf "%s\n" "${arr[@]}" | paste -sd,
a,b,c

(observe que o paste -sd, aqui é muito genérico "transforme este conjunto de itens separados por novas linhas em uma lista separada por vírgula")

    
por 29.04.2014 / 23:01
1
$ w=(a b c)

$ IFS=, eval 'echo "${w[*]}"'
a,b,c

Nota lateral, não somos reinventando a roda aqui?

    
por 30.04.2014 / 06:50
0

Para o array a=(1 2 3 4 5)

Se você pode modificar o array:

for (( i=$((${#a[@]}-1)); i-->0; )); do a[i]+=","; done
echo "${a[@]}"
1, 2, 3, 4, 5

$(( ${#a[@]} - 1 )) calcula o último índice de array, mas um a[i]+="," acrescenta uma string.

Se você quiser fazer isso em uma função:

print_with_commas() {
        while [[ $# -gt 1 ]];do echo -n "$1, ";shift;done;echo "$1"
}
print_with_commas "${a[@]}"
1, 2, 3, 4, 5

Retire cada argumento da função, exceto o último, e eco com ", " anexado sem nova linha. Então, faça eco do último argumento e nova linha.

    
por 30.04.2014 / 03:12
0

verifique o seguinte script

$ cat run.sh
#!/bin/bash
echo example 1
for i in a b c; do echo "${i},"; done
echo example 2
for i in a b c; do echo "${i},"; done|sed '$s/,//'
echo example 3
for i in a b c; do echo "${i}"; done|sed '$!s/$/,/'
echo example 4
SEP=''; for i in a b c; do printf "${SEP}${i}"; SEP=',\n'; done; printf '\n'
echo example 5
STR=''; SEP=''; for i in a b c; do STR="${STR}${SEP}${i}"; SEP=,; done; echo $STR
echo example 6
echo 'a,b,c,'||sed 's/^\(.*\),\(^,\)*$//'
echo example 7
echo 'a,b,c,'|sed 's/.\w*$//'

Fornece a seguinte saída

$ . run.sh
example 1
a,
b,
c,
example 2
a,
b,
c
example 3
a,
b,
c
example 4
a,
b,
c
example 5
a,b,c
example 6
a,b,c
example 7
a,b,c

exemplo 1: nosso loop for realmente produz linhas. O echo $x transforma isso em uma única linha.

exemplo 2: você pode dizer ao sed para processar apenas a última linha

exemplo 3: você pode dizer ao sed para processar todos menos a última linha

exemplo 4: você pode programar o loop for que você faz algum processamento especial quando ele é ececutado na primeira vez: não prefixar ', \ n' na linha. Mas em muitos casos você não sabe quando é expulso da última vez

exemplo 5: o mesmo do exemplo 4, mas você não produz linhas, mas simplesmente uma string

exemplo 6: diga ao sed para remover a última ocorrência de uma string em uma linha

exemplo 7: diga ao sed para remover o último caractere sem espaço em branco de uma linha

    
por 30.04.2014 / 08:54
-1

Por que você realmente precisa remover a vírgula última ?

Você está bagunçando as coisas e depois tenta limpar a bagunça depois, em vez de pensar corretamente sobre o problema em primeiro lugar.

Há uma solução quando você vê a vírgula como não localizada depois de cada item, mas na frente de cada item.

for i in a b c; do
  u="${u:+$u, }$i"
done
echo $u

Veja substituição de parâmetro bash .

Resultado:

a, b, c
    
por 10.08.2018 / 10:56