Estou trabalhando com um arquivo bash_history contendo blocos com o seguinte formato:#unixtimestamp\ncommand\n
aqui está um exemplo do arquivo bash_history:
#1713308636
cat > ./initramfs/init << "EOF"
#!/bin/sh
/bin/sh
EOF
#1713308642
file initramfs/init
#1713308686
cpio -v -t -F init.cpio
#1713308689
cpio -v -t -F init.cpio
#1713308690
ls
#1713308691
ls
Meu objetivo é desduplicar totalmente os blocos, ou seja, tanto o carimbo de data/hora quanto os comandos associados. Tentei usar awk
, mas essa abordagem processa as linhas individualmente, não as considerando como parte de um bloco.
Ouvi dizer que o uso ignoredups
evita a desduplicação, mas não funcionará neste caso ( a menos que você digite novamente o comando exato ) porque o comando duplicado já está lá.
Eu apreciaria sugestões sobre uma maneira mais eficaz de conseguir essa desduplicação.
EDIT: conforme sugerido por Ed Morton no comentário, aqui está o resultado esperado:
#1713308636
cat > ./initramfs/init << "EOF"
#!/bin/sh
/bin/sh
EOF
#1713308642
file initramfs/init
#1713308686
cpio -v -t -F init.cpio
#1713308690
ls
como solução alternativa, adiciono a funcionalidade de exclusão a este programa . mas ainda estou aberto a outras abordagens que usam comandos existentes.
Você não mostrou sua tentativa no awk, mas o seguinte programa awk imprime entradas no sentido de
onde o comando é único. O programa é:
A saída:
Observe que caso os "comandos" como
são salvos no arquivo, o programa awk acima irá simplesmente ignorá-los, por exemplo:
O programa pode ser ajustado para acomodar casos como este, mas requer especificação mais precisa do problema. Por exemplo, como lidar com:
Usando Perl, você pode fazer:
A grande suposição é que isso
^#[0-9]{10}\n
sempre identificará positivamente o início de uma entrada no arquivo.O comando é um pouco denso, mas a lógica por trás dele é:
^#[0-9]{10}\n
como separador de registros, sem consumir o separador (<> =~ /^#[0-9]{10}\n.*?(?=^#[0-9]{10}\n|\z)/smg
);Detalhamento do regex:
^#[0-9]{10}\n.*?(?=^#[0-9]{10}\n|\z)
: corresponderá a uma linha começando com um#
caractere, seguido por 10 dígitos e uma nova linha; ele irá então corresponder preguiçosamente a qualquer coisa (incluindo novas linhas) até que uma nova ocorrência^#[0-9]{10}\n
ou o final da string (\z
) seja encontrada (evitando capturar a ocorrência recém-encontrada de^#[0-9]{10}\n
na correspondência atual usando uma asserção antecipada de comprimento zero (?=
) e permitindo que a próxima partida o capture);s
permitirá.
combinar novas linhas,m
permitirá^
e$
combinará antes e depois de uma nova linha eg
permitirá capturar múltiplas ocorrências do padrão na string.Funciona bem na sua entrada de amostra; Também testei com comandos vazios (um carimbo de data/hora após outro carimbo de data/hora).
Se forem encontradas entradas duplicadas, a primeira entrada será mantida e as posteriores serão descartadas.