Como ignorar letras usando classificar para números
Como posso fazer sortou awkignorar letras ao classificar usando números em um campo específico? Tenho os seguintes dados em meu arquivo de texto:
name name space 2018
name2 name2 space (active 2020)
name1 name1 space (c. 2019)
Quero que o comando ignore "(", ")", "c." E "ativo", para que possa classificar os dados usando apenas o ano.
Estou procurando esta saída:
name name space 2018
name1 name1 space (c. 2019)
name2 name2 space (active 2020)
Respostas
Extraia a parte apropriada do último campo e adicione-o como um campo classificável por conta própria. Classifique nesse campo. Remova o campo adicionado temporariamente para que fiquemos apenas com os dados originais
awk '{y = $NF; gsub("[^[:digit:]]", "", y); printf "%s\t%s\n", y, $0}' file |
sort -k1,1n |
cut -f2-
O gsubcontém uma ER que remove todos os caracteres não-dígitos do último campo separado por espaços. Você pode executar apenas o awkcomando (obviamente sem o caractere de pipeline à direita) para ver o que ele faz com seus dados de entrada. Em seguida, adicione o sortpara ver o que isso faz.
Para classificar na seqüência mais à direita de dígitos decimais em cada linha, você pode extraí-los e colocá-los na frente, classificar e remover depois:
<file LC_ALL=C sed '
h; # save pattern space (current line) onto hold space
s/[^0123456789]*$//; # remove non-digit characters from the end
s/^.*[^0123456789]//; # remove everything up to the last non-digit
G; # append \n and hold space to pattern space
s/\n/:/; # replace that \n with :' |
sort -n |
cut -d: -f2-
Aplicação de opção -V(classificação natural) e classificação pelo primeiro campo
sort -Vk1,1 file
name name space 2018
name1 name1 space (c. 2019)
name2 name2 space (active 2020)
Para alguns casos complicados:
sort -Vk1,1 -k5 file
Após os comentários, decidi acrescentar:
awk 'BEGIN {PROCINFO["sorted_in"]="@val_num_asc"} {a=$0; gsub(/[^0-9]/, ""); D[a]=$0}; END {for(i in D)print i}' file
Eu transfiro todos os números para os valores da matriz com chaves na forma de uma string e especifico a ordem de classificação: PROCINFO["sorted_in"]="@val_num_asc"
usando Raku (anteriormente conhecido como Perl 6)
É mais difícil do que parece. Comecei dobrando o número de linhas no arquivo de teste, depois pensei na melhor maneira de abordar esse problema. Uma abordagem pode ser dividir em espaços em branco, no entanto, isso também seria dividido em espaços em branco entre parênteses, portanto, algumas linhas teriam 4 colunas, enquanto outras teriam cinco.
O código a seguir classifica em uma regex de "ano" de 4 dígitos, ignorando colunas (ou seja, "campos de texto", no jargão do OP). O código funciona desde que haja apenas um (1) ano por linha:
raku -e 'my $a = lines(); my @b = $a.comb(/ \d**4 /).pairs; my $c = @b.sort(*.values)>>.keys.flat; $a[$c.flat]>>.put;' sort_year.txt
name name space 2018
name0 name space 2018
name1 name1 space (c. 2019)
name4 name1 space (c. 2019)
name2 name2 space (active 2020)
name3 name2 space (active 2020)
O código acima combina um padrão regex de 4 dígitos ( @b); um índice de ordenação ( $c) é derivado (de @b) e, em seguida, as linhas ( $a) são reordenadas com base na "chave" de indexação ( $c).
Este é o arquivo de entrada, para quem deseja experimentar em casa:
~$ cat sort_year.txt
name name space 2018
name2 name2 space (active 2020)
name1 name1 space (c. 2019)
name0 name space 2018
name3 name2 space (active 2020)
name4 name1 space (c. 2019)
https://raku.org/
Quando me deparo com tarefas de classificação complicadas, acho que o msort geralmente pode lidar com elas.
O snippet de código:
# Utility functions: print-as-echo, print-line-with-visual-space.
pe() { for _i;do printf "%s" "$_i";done; printf "\n"; } pl() { pe;pe "-----" ;pe "$*"; }
pl " Input data file $FILE:" head $FILE
pl " Results, msort:"
msort -l -j -q -n -1 --comparison-type hybrid $FILE
produz:
-----
Input data file data1:
name name space 2018
name2 name2 space (active 2020)
name0 xx2021yy
name1 name1 space (c. 2019)
-----
Results, msort:
name name space 2018
name1 name1 space (c. 2019)
name2 name2 space (active 2020)
name0 xx2021yy
Resumidamente: omite log, quiet, cada linha é um registro, classifique no campo mais à direita, comparação híbrida.
Executar em:
Environment: LC_ALL = C, LANG = C
(Versions displayed with local utility "version")
OS, ker|rel, machine: Linux, 3.16.0-10-amd64, x86_64
Distribution : Debian 8.11 (jessie)
bash GNU bash 4.3.30
Na página de manual:
-n,--position <POS>(,<POS>)
Sort on the specified POS or contiguous range of POSs, where a
POS is of the form <field number>(.<character number>). Both
counts begin at one. Field numbers but not character numbers
may be negative, in which case they are counted from the right.
Thus, 1.2 is the second character of the first field; -2.1 is
the first character of the next to last field.
O código msort pode ser encontrado em muitos repositórios, aqui estão mais informações:
msort sort records in complex ways (man)
Path : /usr/bin/msort
Version : 8.53
Type : ELF 64-bit LSB executable, x86-64, version 1 (SYS ...)
Help : probably available with -h,--help
Repo : Debian 8.11 (jessie)
Home : http://www.billposer.org/Software/msort.html (pm)
Muitas felicidades ... saúde, drl
comando
awk '{sub(/)$/,"",$0);print }' filename|sort -k5| awk 'NR>1{$0=$0")"}1'
resultado
name name space 2018
name1 name1 space (c. 2019)
name2 name2 space (active 2020)