classifica uma lista baseada na porção datetime dos registros em que a posição datetime no registro pode variar

1

Eu quero classificar uma lista na parte datetime de seu nome.

Isso é possível usando a ordenação? Não consigo especificar a coluna de classificação, pois a coluna pode variar conforme mostrado na entrada de amostra abaixo.

swid_ds_install_user_20171227172654_20425.log
package_user_20171227172949_5627.log
swid_state_definition_user_20171227162839_6515.log
swid_ds_install_user_20171227172732_23839.log
swid_appsrv_stop_user_20171227172258_27116.log
package_user_20171227172610_16198.log
swid_state_definition_user_20171227172344_322.log
package_user_20171227233634_23845.log
package_user_20171227162858_7082.log

Eu posso reverter a ordem dos campos por meio de, por exemplo,

awk -F_ '{for (i=NF;i>0;i--){printf $i"_"};printf "\n"}'

classifique com -d_ -k2,2 e, em seguida, inverta a ordem dos campos para reter o nome do arquivo original - purgando os delimitadores residuais com, e. sed - mas isso fica estranho.

awk -F_ '{for (i=NF;i>0;i--){printf $i"_"};printf "\n"}' | sort -t'_' -k2,2 \
| awk -F_ '{for (i=NF;i>0;i--){printf $i"_"};printf "\n"}' | sed 's/^_//' \ 
| sed 's/_$//'

Como você abordaria isso?

Eu estava pensando nas linhas de usar sed para dividir a parte de datetime via regex e pipe em sort e depois usar algum built-in para recuperar o nome completo do arquivo e não apenas a regex correspondente, ao imprimir a saída. / p>

Esperando não ter produzido outra cópia, não posso resumir a declaração do problema

    
por HenrikJson 28.12.2017 / 11:24

3 respostas

2
awk -F_ '{print $(NF-1), $0}' | sort -k1,1 -n | cut -d' ' -f2-

Isso usa awk com _ como o separador de campo para copiar o segundo último campo ( datetime ) para o início da linha e, em seguida, usa sort para classificar a entrada numericamente apenas nesse campo, seguido por cut para remover o campo extra.

Exemplo de saída com sua entrada de amostra salva em um arquivo chamado file :

$ awk -F_ '{print $(NF-1), $0}' file  | sort -k1,1 -n | cut -d' ' -f2-
swid_state_definition_user_20171227162839_6515.log
package_user_20171227162858_7082.log
swid_appsrv_stop_user_20171227172258_27116.log
swid_state_definition_user_20171227172344_322.log
package_user_20171227172610_16198.log
swid_ds_install_user_20171227172654_20425.log
swid_ds_install_user_20171227172732_23839.log
package_user_20171227172949_5627.log
package_user_20171227233634_23845.log

Isso pressupõe que o datetime sempre estará no segundo último campo. Se isso não for não , então se você estiver usando o GNU awk, você pode capturar o padrão que parece como um datetime, e prefixar isso ao início da linha:

$ awk -F_ '{match($0,"_(20[0-9]{12})_",dt); print dt[1], $0}' file |
    sort -k1,1 -n | cut -d' ' -f2-

mas eu estaria inclinado a usar perl neste caso.

A função match() do GNU awk recebe um terceiro argumento opcional, o nome de uma variável de matriz para armazenar todas as correspondências capturadas. Neste caso, haverá apenas uma captura, para que seja armazenada no primeiro elemento. da matriz, por exemplo %código%. IIRC, POSIX awk ainda não tem como capturar combinações de regex.

BTW, a suposição agora é que o ano é > = 2000. Ajuste o regex para se adequar se isso não for sempre verdadeiro para seus dados de entrada.

    
por 28.12.2017 / 13:07
1

Você pode usar zsh globs como:

printf '%s\n' *_user_*.log(oe:'REPLY=${REPLY##*user_}':)

em que oe:...: define uma ordem de classificação com base na expressão especificada. Aqui, onde selecionamos a parte do nome do arquivo à direita de "user _".

Para classificar os últimos 2 _* :

printf '%s\n' *_*_*.log(oe:'REPLY=${(M)REPLY%_*_*}':)
    
por 28.12.2017 / 11:47
0

Parece que isso deve funcionar:

$ perl -e 'sub key($) { $_[0] =~ /(\d+)_\d+\.log$/; return $1; }; 
     @lines = <>; print sort {key($a) cmp key($b)}  @lines;'  < files
swid_state_definition_user_20171227162839_6515.log
package_user_20171227162858_7082.log
swid_appsrv_stop_user_20171227172258_27116.log
swid_state_definition_user_20171227172344_322.log
package_user_20171227172610_16198.log
swid_ds_install_user_20171227172654_20425.log
swid_ds_install_user_20171227172732_23839.log
package_user_20171227172949_5627.log
package_user_20171227233634_23845.log

A sub-rotina key seleciona a sequência de dígitos com base no fato de que o datetime parece sempre ser a penúltima parte do nome do arquivo, antes do campo .log e do outro número. Em seguida, lemos as linhas de entrada e as imprimimos usando a saída de key() como a chave de classificação.

O sort de Perl pode receber um bloco de código embutido que obtém os valores a serem comparados como $a e $b , e cmp retorna menos, então, igual ou maior que (comparando como sequências).

Se o local do carimbo de data / hora puder variar mais, poderemos alterar o sub para escolher uma sequência de 14 dígitos em qualquer lugar da string, por exemplo, separados por sublinhados aqui:

sub key($) { $_[0] =~ /_(\d{14})_/; return $1; }
    
por 28.12.2017 / 11:55

Tags