sort (diferença entre a opção padrão e numérica -n)

1

Nas páginas man, temos a seguinte descrição da opção --numeric-sort do comando sort.

-n, --numeric-sort
              compare according to string numerical value

Eu assumo, por valor numérico de string, queremos dizer comparando cada caractere de string consecutivamente pelo seu valor ASCII?

As páginas de informações são lidas

‘-n’
‘--numeric-sort’
‘--sort=numeric’
     Sort numerically.  The number begins each line and consists of
     optional blanks, an optional ‘-’ sign, and zero or more digits
     possibly separated by thousands separators, optionally followed by
     a decimal-point character and zero or more digits.  An empty number
     is treated as ‘0’.  The ‘LC_NUMERIC’ locale specifies the
     decimal-point character and thousands separator.  By default a
     blank is a space or a tab, but the ‘LC_CTYPE’ locale can change
     this.

     Comparison is exact; there is no rounding error.

     Neither a leading ‘+’ nor exponential notation is recognized.  To
     compare such strings numerically, use the ‘--general-numeric-sort’
     (‘-g’) option.

Depois de ler os dois documentos, ainda não vejo explicitamente explicado qual ordem de agrupamento é usada para a opção -n.

Como a opção --numeric-sort se diferencia do padrão? Meu palpite ingênuo seria que os números têm precedência sobre as letras, mas não estou lendo isso na documentação.

E qual documentação declara isso explicitamente, ou seja, onde eu encontrei essa informação apenas pesquisando a documentação?

    
por Mussé Redi 30.07.2017 / 21:55

2 respostas

3

Por padrão, sort classifica caractere por caractere usando uma ordem de classificação especificada pelo local. Geralmente isso é muito próximo da ordem ASCII, mas pode haver algumas variações regionais. Na página do manual:

***  WARNING  ***  The  locale  specified  by the environment affects sort order.
Set LC_ALL=C to get the traditional sort order that uses native byte values.

Valor de byte nativo geralmente significa valor ASCII, portanto, os dígitos vêm antes das letras maiúsculas, que vêm antes das letras minúsculas. Mas a ordenação ainda é caractere por caractere, então 10 vem antes de 2 porque 1 vem antes de 2 .

Quando a opção -n ou --numeric-sort é especificada, as execuções de dígitos são tratadas como números (não caracteres individuais) e classificadas numericamente do menor para o maior.

A documentação não está totalmente explícita nos detalhes, portanto, aqui estão as regras do sinalizador -n derivado experimentalmente:

  1. As linhas que começam numericamente são classificadas por valor numérico (números menores vêm primeiro)
  2. Caracteres finais em linhas numéricas não afetam a parte numérica, mas os caracteres finais são classificados alfanumericamente se a parte numérica for a mesma.
  3. As linhas que começam não numericamente são classificadas como se fossem zero e, em seguida, pela regra 2.

Observe:

$ printf %s\n 2z 111 10 20b 20a aa2 aa10 | sort -n
aa10
aa2
2z
10
20a
20b
111

Pela Regra 3, as linhas aa10 e aa2 são tratadas como zeros e classificadas pelos caracteres restantes (incluindo os dígitos, que são considerados caracteres).

Pela Regra 2, as linhas 2z , 20a e 20b são tratadas como números e o caractere final só entra em vigor quando os números são iguais.

E pela regra 1, todas as linhas que começam com um número são classificadas por valor numérico.

Sem o sinal -n , a classificação é feita caractere por caractere, em que os caracteres do dígito vêm antes dos caracteres da carta. Observe:

$ printf %s\n 2z 111 10 20b 20a aa2 aa10 | sort
10
111
20a
20b
2z
aa10
aa2
    
por 30.07.2017 / 22:57
4

Quando você tem números com vários dígitos, sort -n considera o número inteiro ; por padrão, o arquivo

3
2
1
20
30

classifica assim:

1
2
20
3
30

que provavelmente não é o que você queria. Com -n , você recebe:

1
2
3
20
30

A classificação numérica também lida com números negativos, pontos decimais e separadores de milhares (conforme determinado pela sua localidade). Se houver texto "não numerado" à direita, ele será ignorado na ordem de classificação. Se a linha começa com algo não numérico, essa linha é contada como 0.

Mais exatamente, a lógica é assim: a chave de ordenação (primária) é uma sequência numérica inicial . (Isto é, "o número inicia cada linha".) Esta cadeia é definida para consistir em possíveis espaços em branco, um sinal de menos, zero ou mais dígitos e possivelmente . e , (ou tanto faz). Letras à direita não levam em consideração - elas não fazem parte do "número". Se a linha não começar com números, isso é tratado como um número invisível ("vazio") igual a 0. (Ou, "um número com zero dígitos".)

Portanto, tendo classificado "o número" (compare usando -k para fornecer uma chave de classificação), se houver alguma linha restante, essas linhas serão classificadas com a classificação padrão . (Isto é, 1a antes de 1b - e 1a20 antes de 1a3 .) A linha inteira é classificada desta forma, não a linha, exceto a chave de classificação, que fornece algumas comportamento neste caso ( 0cookies ordena antes biscuits - para a classificação secundária, não há "0 invisível" adicionado).

Em geral, use -n quando você realmente quiser classificar linhas (ou campos) que consistem em números. Se você tem um monte de coisas que não são números, ou são números mistos com outras strings, você ainda obterá um resultado consistente, mas pode não ser o que você deseja.

Se você tiver um misto de letras e números (e linhas que contenham ambos), talvez prefira -V , o que faz uma versão classificar de acordo com regras especiais que dividem a string em componentes lógicos - mas cuidado porque isso colocará 1.10 maior do que 1.9 .

    
por 30.07.2017 / 22:50

Tags