Script de shell para classificar por coluna de data usando o comando Linux 'sort'

0

Eu tenho um arquivo chamado session.log Ele contém alguns dados de texto. 1a coluna contém o número de série. A segunda coluna contém o nome de usuário. A terceira coluna contém a última data de login. A quarta coluna contém o resultado.

Um usuário efetuou login várias vezes. Preciso encontrar a última data de login para cada usuário único. Então eu escrevi um script de shell. A saída exibirá as linhas com a última data de login (3ª coluna) para cada usuário único (2ª coluna). A saída não deve conter o mesmo nome de usuário várias vezes.

$ cat session.log 
1 u1 2018-05-19 pass
2 u2 2018-06-15 pass
3 u3 2018-05-18 pass
4 u4 2018-05-17 pass
5 u2 2018-05-14 pass
6 u4 2018-07-11 pass
7 u1 2018-05-16 pass
8 u3 2018-05-13 pass
9 u1 2018-08-12 pass
10 u1 2018-05-10 pass

O que eu tentei:

( awk {print} session.log | cut -f2 -d' ' | sort | uniq ) > store.txt
for line in $(cat "store.txt")
do
    touch "$line.txt"
    grep "$line" session.log > "$line.txt"
    temp=$(sort -k3 "$line.txt" | awk 'END{print}')
    echo $temp > "$line.txt"
    cat "$line.txt"
done

Resultado

$ ./sort.sh
9 u1 2018-08-12 pass
2 u2 2018-06-15 pass
3 u3 2018-05-18 pass
6 u4 2018-07-11 pass

O script de shell funciona para o formato de data (aaaa-mm-dd) e (aaaa / mm / dd). Existe algum código melhor para fazer o mesmo trabalho? Usando awk como fazemos isso?

EDITAR:

$ cat sort.sh
( awk {print} session.log | cut -f2 -d' ' | sort | uniq ) > store.txt
for line in $(cat "store.txt")
do
    #touch "$line.txt"
    grep "$line" session.log > "$line.txt"
    echo $(sort -k3 "$line.txt" | awk 'END{print}')
    #temp=$(sort -k3 "$line.txt" | awk 'END{print}')
    #echo $temp > "$line.txt"
    #cat "$line.txt"
done
rm -f store.txt
    
por Dipankar Nalui 16.06.2018 / 12:45

1 resposta

2
$ sort -k 3,3r session.log | awk '!seen[$2]++ { print }'
9 u1 2018-08-12 pass
6 u4 2018-07-11 pass
2 u2 2018-06-15 pass
3 u3 2018-05-18 pass

(O { print } pode ser removido completamente, só estou incluindo para mostrar o que acontece. A ação padrão é imprimir todo o registro de entrada se a condição for verdadeira.)

Isso classifica o arquivo que você possui, diminuindo as datas (a data mais recente primeiro). O programa awk lê os dados classificados e imprime a primeira entrada encontrada para cada usuário. A variável seen é uma matriz / hash associativa que usa os nomes de usuários como chaves. Se seu valor for zero para um usuário, esse usuário ainda não foi visto e, portanto, a linha do arquivo será impressa.

Seu código com minhas anotações:

# get list of unique usernames from log:
( awk {print} session.log | cut -f2 -d' ' | sort | uniq ) > store.txt

# shorter equivalent:
# cut -d ' ' -f2 <session.log | sort -u >store.txt

# loop over the usernames:
for line in $(cat "store.txt")
do
    # get entries related to this user:
    grep "$line" session.log > "$line.txt"

    # echo the last entry:
    echo $(sort -k3 "$line.txt" | awk 'END{print}')

    # shorter equivalent of both of the above commands:
    # awk -v user="$line" '$2 == user { print }' session.log | sort -k3,3 | tail -n 1
done
rm -f store.txt

Portanto, uma abordagem alternativa baseada em seu loop de shell:

cut -d ' ' -f2 <session.log | sort -u |
while read username; do
    awk -v user="$username" '$2 == user { print }' session.log | sort -k 3,3 | tail -n 1
done

Novamente, o { print } pode ser deixado de fora do script awk acima.

Isso ainda classifica subconjuntos de log de sessão uma vez para cada usuário, o que é uma espécie de desperdício.

Pré-classificando o registro diminuindo as datas:

sort -k3,3r -o sorted.log session.log

cut -d ' ' -f2 <session.log | sort -u |
while read username; do
    awk -v user="$username" '$2 == user { print; exit }' sorted.log
done

rm sorted.log

Isso ainda requer que digitalizemos o log a partir do topo uma vez por usuário. A melhoria natural é permitir que awk acompanhe o que os usuários viram e quais usuários não foram vistos, o que dá a minha resposta no topo.

    
por 16.06.2018 / 13:05