Como o uniq funciona? [duplicado]

1

Não confunda essa pergunta com uma duplicata de "o que é diferença b / w sort -u e sort | uniq"

Este é essencialmente um programa de contagem de palavras

A confusão gerada pelo seguinte comando é motivo para fazer esta pergunta:

    root@sanctum:~/datascience# cat data 
    this is a file that is supposed to be a file

isto dá saída incorreta:

root@sanctum:~/datascience# cat data | sed 's/ /\n/g' | uniq -c
      1 this
      1 is
      1 a
      1 file
      1 that
      1 is
      1 supposed
      1 to
      1 be
      1 a
      1 file

Piping a saída para classificar e, em seguida, para uniq dá a resposta perfeita -

root@sanctum:~/datascience# cat data | sed 's/ /\n/g' | sort |uniq -c
      2 a
      1 be
      2 file
      2 is
      1 supposed
      1 that
      1 this
      1 to

saída de quando canalizada apenas para ordenar:

root@sanctum:~/datascience# cat data | sed 's/ /\n/g' | sort 
a
a
be
file
file
is
is
supposed
that
this
to

como o número da linha de aparência de uma linha afeta a contagem das ocorrências no arquivo? eu não sei como frase, mas você começa o ponto

Basicamente, porque não posso cat data | sed 's/ /\n/g' | uniq -c dar o resultado desejado?

    
por juggernauthk108 31.10.2016 / 20:17

1 resposta

2

Este não é um comportamento aleatório. De man uniq :

  

Nota: 'uniq' não detecta linhas repetidas, a menos que sejam adjacentes. Você pode querer classificar a entrada primeiro ou usar 'sort -u' sem 'uniq'. Além disso, comparações honram as regras especificadas por 'LC_COLLATE'.

Essencialmente, uniq , por padrão, só funciona na entrada classificado . É assim, por design, em outras palavras.

Sua principal pergunta, no entanto, é:

  

como o número da linha de aparência de uma linha afeta a contagem das ocorrências no arquivo

Para responder a essa pergunta, você realmente precisa ver o código-fonte:

 while (!feof (stdin))
    {
      char *thisfield;
      size_t thislen;
      if (readlinebuffer_delim (thisline, stdin, delimiter) == 0)
        break;
      thisfield = find_field (thisline);
      thislen = thisline->length - 1 - (thisfield - thisline->buffer);
      if (prevline->length == 0
          || different (thisfield, prevfield, thislen, prevlen))
        {
          fwrite (thisline->buffer, sizeof (char),
                  thisline->length, stdout);

          SWAP_LINES (prevline, thisline);
          prevfield = thisfield;
          prevlen = thislen;
        }
    }

A chave aqui é que o arquivo é lido linha por linha e a comparação pode ser feita apenas com a linha atual e a anterior na função different() , que retorna True se as linhas não forem as mesmas, Falso se eles são os mesmos. A razão para isso é que, se você fosse comparar com todas linhas, provavelmente precisaria de grande quantidade de memória se houvesse um grande número de linhas. Isso não é prático e diminuiria a velocidade de uniq consideravelmente

    
por Sergiy Kolodyazhnyy 31.10.2016 / 20:21