Imprimir todos os dados relacionados a um determinado campo

2

Considerando o arquivo abaixo:

foo,5
foo,7
foo,9
boo,5
boo,10
boo,10

O que estou procurando é imprimir todos os dados em $2 relacionados a $1 em um registro.

Para este exemplo, o resultado necessário será:

foo,5,7,9
boo,5,10

Por favor avise,

    
por Eng7 16.08.2015 / 15:48

6 respostas

4

Uma solução awk :

awk 'BEGIN{OFS=FS=","}!(($1,$2)in c){c[$1,$2]=1;r[$1]=r[$1] OFS $2}
            END{for(i in r){print i r[i]}}' file
  1. Defina OFS=FS para consistência.
  2. Use a matriz multidimensional de awk para lembrar o $2 valores encontrados até agora. Apenas 'prosseguir' se não houver correspondência ( !(($1,$2)in c) ).
  3. Forneça um valor 'fictício' para o array multidimensional no primeiro encontro de uma nova chave.
  4. Concatene a sequência de saída desejada em outro array por conveniência.
  5. No END , imprima o loop.
    • Observe que a iteração de loop não está em nenhuma ordem específica, você pode usar os recursos de classificação de awk , se necessário.
por 16.08.2015 / 18:32
3

Analise os dados em "hashes" ou "matrizes associativas" ou "dicionários" ou seja lá como eles são chamados:

perl -F, -lane '$first{$F[0]}->{$F[1]} = (); END { print join(",", $_, sort { $a <=> $b } keys %{ $first{$_} } ) for keys %first }' < inputfile
    
por 16.08.2015 / 17:12
2

Uma solução no bash sem awk:

$ cat bla.txt 
foo,5
foo,7
foo,9
boo,5
boo,10
boo,10

$ { buffer="";
  while read i ; do
    key="${i%,*}" ;
    if [[ "$key" == "$oldkey" ]] ; then
      idx="${i#*,}";
      if [[ ! "$idx" == "$oidx" ]] ; then
        buffer+=",$idx" ;
        oidx="$idx";
      fi ;
    else
      test -z $buffer || echo $buffer ;
      oldkey="$key" ;
      buffer="$i" ;
      oidx="${i#*,}" ;
    fi ;
  done ; echo $buffer ; } < bla.txt
foo,5,7,9
boo,5,10
$

Não é bonito nem curto, mas funciona. Eu também estaria interessado em ver uma solução com o awk.

    
por 16.08.2015 / 17:39
2

Você também pode usar a ferramenta q - Texto como banco de dados . É um script Python de arquivo único. Usando você pode fazer:

$ cat bla.txt 
foo,5
foo,7
foo,9
boo,5
boo,10
boo,10

$ qry="select c1, group_concat(c2) from bla.txt group by c1" ;
$ q -d, "$qry" | sed -r 's/(,[^,]*)//g'
boo,5,10
foo,5,7,9

Isso pressupõe que o arquivo de entrada seja classificado. O sed de rastreamento só é necessário para remover as duplicatas na sua entrada. Se você não tem nenhum, omitir o sed. Se você precisar de uma ordem de saída específica, adicione uma cláusula "ORDER BY".

    
por 16.08.2015 / 22:31
2

Com gnu datamash :

datamash -t ',' -s -g 1 unique 2 <infile

a ordem dos valores na saída será diferente, embora eles sejam classificados antes de serem processados:

boo,10,5
foo,5,7,9
    
por 27.09.2015 / 18:35
1

usando uma combinação de cut , grep e sort , com uma pequena ajuda de formatação de sed e tr . Além disso, seu arquivo de saída será classificado em palavras-chave e valores para cada palavra-chave:

#get sorted, unique keyword list
cut -d, -f 1 file | sort -u |\
while read keyword ; do
  #echo keyword and sorted, unique occurrences of values
  #for keyword as output
  echo $keyword,$(grep "^$keyword," file | cut -d, -f2 |\
              sort -u | tr '\n' ',' | sed 's/,$//' )  \
  >> sorted_file
done

o one-liner:

cut -d, -f 1 file | sort -u | while read keyword ; do echo $keyword,$(grep "^$keyword," file | cut -d, -f2 | sort -u | tr '\n' ',' | sed 's/,$//' )  >> sorted_file ; done
    
por 16.08.2015 / 20:55