Remova toda a palavra duplicada da string usando o shell script


12

Eu tenho uma string como

"aaa,aaa,aaa,bbb,bbb,ccc,bbb,ccc"

Eu quero remover a palavra duplicada da string e a saída será como

"aaa,bbb,ccc"

Eu tentei este código fonte

$ echo "zebra ant spider spider ant zebra ant" | xargs -n1 | sort -u | xargs

Está funcionando bem com o mesmo valor, mas quando dou meu valor de variável, também está mostrando todas as palavras duplicadas.

Como posso remover um valor duplicado.

ATUALIZAR

Minha pergunta é adicionar todo o valor correspondente em uma única string, se o usuário for o mesmo. Tenho dados como este ->

   user name    | colour
    AAA         | red
    AAA         | black
    BBB         | red
    BBB         | blue
    AAA         | blue
    AAA         | red
    CCC         | red
    CCC         | red
    AAA         | green
    AAA         | red
    AAA         | black
    BBB         | red
    BBB         | blue
    AAA         | blue
    AAA         | red
    CCC         | red
    CCC         | red
    AAA         | green

Ao codificar, busco todos os usuários distintos e concatenarei a sequência de cores com êxito. Para isso, estou usando o código -

while read the records 

    if [ "$c" == "" ]; then  #$c I defined global
        c="$colour1"
    else
        c="$c,$colour1" 
    fi

Quando imprimo essa variável $ c, recebo a saída (para o usuário AAA)

"red,black,blue,red,green,red,black,blue,red,green,"

Quero remover cores duplicadas. A saída desejada deve ser como

"red,black,blue,green"

Para esta saída desejada, usei o código acima

 echo "zebra ant spider spider ant zebra ant" | xargs -n1 | sort -u | xargs

mas está exibindo a saída com valores duplicados.

"vermelho, preto, azul, vermelho, verde, vermelho, preto, azul, vermelho, verde", obrigado


3
Por favor, esclareça o que há de errado com o que você está usando. Não entendo o que você quer dizer com "quando eu der o valor da minha variável". Que valor você dá? Onde isso falha?
terdon

echo 'aaa aaa aaa bbb bbb ccc bbb ccc' | xargs -n1 | sort -u | xargsaaa bbb ccc.. então você precisa mostrar o código exato que você cansado e saída que você tem .. com a corda na variável:s='aaa aaa aaa bbb bbb ccc bbb ccc'; echo "$s" | xargs -n1 | sort -u | xargs
Sundeep

o valor da sequência vem dinamicamente. Está imprimindo o mesmo valor (contém valor duplicado).
Urvashi 23/03

1
sim, mostre o código que falhou, caso contrário, como saberíamos o que poderia ter dado errado?
Sundeep 23/03

O pedido importa?
Jacob Vlijm 23/03

Respostas:


12

Mais um awk, apenas por diversão:

$ a="aaa bbb aaa bbb ccc aaa ddd bbb ccc"
$ echo "$a" | awk '{for (i=1;i<=NF;i++) if (!a[$i]++) printf("%s%s",$i,FS)}{printf("\n")}'
aaa bbb ccc ddd 

A propósito, até sua solução funciona bem com variáveis:

$ b="zebra ant spider spider ant zebra ant" 
$ echo "$b" | xargs -n1 | sort -u | xargs
ant spider zebra

Abordagem pura. O único ajuste que tive que fazer foi usar em %svez de %s%s. A razão é que eu estava fazendo um loop for nos resultados e dois espaços em branco causaram alguns desafios com as correspondências regex.
JeremyCanfield

9

Com tr, sorteuniq

echo "zebra ant spider spider ant zebra ant" | tr ' ' '\n' | sort | uniq

ou

echo "zebra ant spider spider ant zebra ant" | tr ' ' '\n' | sort | uniq | xargs 

para obter uma linha


Você precisa adicionar | xargspara se juntar a saída para uma linha novamente
Philippos

4
Ou use sort -u. Ou até um awk '!u[$0]++.
Benoît

2
@ Benoît Uau, eu não sabia sort -u. Eu tenho usado sort | uniqtodo esse tempo. As teclas desperdiçados ...
gardenhead

8
$ echo "zebra ant spider spider ant zebra ant"  | awk -v RS="[ \n]+" '!n[$0]++' 
zebra
ant
spider

1
Muito esperto!!!!
George Vasiliou

@GeorgeVasiliou, obrigado [ou para dizer a verdade, muito preguiçoso :-)]
JJoao

2

Com o gnu sed:

sed ':s;s/\(\<\S*\>\)\(.*\)\<\1\>/\1\2/g;ts'

Você pode adicionar ;s/ */ /gpara remover espaços públicos.

Funções como esta: se uma palavra for uma segunda vez nesta linha, remova-a e comece novamente até que nenhuma publicação seja encontrada.


O que são \<e \>?
Someonewithpc 23/03

@someonewithpc Eles não correspondem a nenhum caractere, mas ao início e ao fim de uma palavra para impedir a correspondência de substrings.
Philippos

Legal, mas isso é portátil? Além disso, as palavras não são separadas por espaço em branco? Parece redundante para não corresponder a espaço em branco seguido pelo final de uma palavra.
someonewithpc

1
@someonewithpc Não, não é padrão, é por isso que escrevi gnu sed . A parte boa é que você não tem que lidar com primeiro e último corda separadamente
Philippos

2
perl -lane '$,=$";print grep { ! $h{$_}++ } @F'

2

Solução awk obrigatória:

$ echo "ant zebra ant spider spider ant zebra ant" | 
   awk -vRS=" " -vORS=" " '!a[$1] {a[$1]++} END{ for (x in a) print x;  } ' ; echo
zebra ant spider 

(A final echoestá lá para a nova linha)


Mais um para o awk! Eu estava construindo também uma solução awk apenas por diversão. Há uma pequena possibilidade de que as palavras sejam impressas em ordem aleatória na seção END, devido à maneira aleatória que o awk itera nas chaves da matriz.
George Vasiliou

Sim, eles serão impressos em uma ordem essencialmente aleatória. A sortsolução também não mantém a ordem original.
23917 ilkkachu

Sim, bom ponto! Mesmo classifique as impressões em ordem diferente da entrada.
George Vasiliou

1
@ilkkachu Na verdade, não precisamos esperar a entrada terminar. Podemos tomar a decisão de imprimir ou não imprimir com uma ligeira modificação no seu código: awk -vRS=" " -vORS=" " '!a[$1]++ {print $1}' ; echoisso preserva o pedido.

1

Pitão

Opção 1

#!/usr/bin/env python
# get_unique_words.py

import sys

l = []
for w in sys.argv[1].split(','):
  if w not in l:
    l += [ w ]
print ','.join(l)

Torne executável e ligue a partir do Bash:

$ ./get_unique_words.py "aaa,aaa,aaa,bbb,bbb,ccc,bbb,ccc"
aaa,bbb,ccc

Ou você pode implementá-lo como uma função Bash, mas a sintaxe é confusa.

get_unique_words(){
  python -c "
l = []
for w in '$1'.split(','):
  if w not in l:
    l += [ w ]
print ','.join(l)"
}

opção 2

Esta opção pode se tornar uma linha, se necessário:

#!/usr/bin/env python
# get_unique_words.py

import sys

s_in = sys.argv[1]
l_in = s_in.split(',') # Turn string into a list.
set_out = set(l_in) # Turning a list into a set removes duplicates items.
s_out = ','.join(set_out) 
print s_out

No Bash:

get_unique_words(){
  python -c "print ','.join(set('$1'.split(',')))"
}

0
cat filename | awk '{ delete a; for (i=1; i<=NF; i++) a[$i]++; n=asorti(a, b); for (i=1; i<=n; i++) printf b[i]" "; print "" }' > newfile

Eu não entendi
Pierre.Vriens

1
Seu código não tem explicação. Sem explicação, é difícil acompanhar o que está acontecendo. Você também parece fazer suposições sobre os dados que parecem errados (campos delimitados por espaço em branco) e sobre a awkimplementação específica que está sendo usada ( asorti()não é uma awkfunção padrão ).
Kusalananda

0

Usando os dados tabulares originais no arquivo chamado file:

sed '1d' file | sort -u |
awk '{ color[$1] = ( color[$1] == "" ? $3 : color[$1] "," $3 ) }
     END { for (user in color) print user, color[user] }'

Isso gera

CCC red
BBB blue,red
AAA black,blue,green,red

As três etapas do pipeline:

  1. O sedcomando remove a primeira linha, que é um cabeçalho que não queremos ler.
  2. O sortcomando nos fornece linhas únicas. Os dados de amostra após a sortaparência

    AAA         | black
    AAA         | blue
    AAA         | green
    AAA         | red
    BBB         | blue
    BBB         | red
    CCC         | red
  3. O awkcomando pega esses dados e produz uma cadeia de caracteres delimitada por vírgula para cada usuário na matriz color(em que o nome de usuário é a chave da matriz). No final (no ENDbloco), todos os dados coletados são emitidos.

-2
a="aaa aaa aaa bbb bbb ccc bbb ccc"
for item in $a
do
   echo $item
done | sort -u | (while read i; do ans="$ans $i"; done ; echo $ans)

Adicione uma explicação sobre como seu código funciona e por que você fez isso e aquilo.
xhienne
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.