remova linhas mais recentes que a data especificada em um arquivo

8

Estou preso em como posso excluir linhas mais recentes que a data especificada. Aqui está um trecho de conteúdo de um arquivo.

buildsave.txt

647919 2013/11/30
647946 2013/11/30
647955 2013/12/01
648266 2013/12/03
648267 2013/12/03
648674 2013/12/04

Gostaria de remover as linhas mais recentes que 03/12/2013, deixando apenas

647919 2013/11/30
647946 2013/11/30
647955 2013/12/01

Como isso pode ser feito através do bash?

Jason G
fonte

Respostas:

4

Se o seu sistema incluir a versão GNU do datecomando, você poderá usá-lo para converter o campo de data (depois de eliminar o final <br>, se presente) em segundos desde a época e comparar diretamente com a data de corte no mesmo formato, por exemplo, no bash

testsecs=$(date +%s --date="2013/12/03")
while IFS= read -r line; do
  read -r x d <<< "$line" 
  if (( $(date +%s --date="${d%<br>}") < $testsecs )); then
    printf '%s\n' "$line"
  fi
done < buildsave.txt

[Observe que isso não executa uma exclusão no local - você precisará salvar os resultados em um arquivo temporário e renomear.]

chave de aço
fonte
Seu senhor me salvou uma dor de cabeça. Era exatamente isso que eu estava procurando!
Jason G
que nojo! Essas datas têm a mesma ordem lexicográfica e cronológica, não há necessidade de convertê-las em números inteiros e executar 5 comandos, criar um arquivo temporário e dois canais por linha!
Stéphane Chazelas
9

Essas datas têm a mesma ordem lexicográfica e cronológica, por isso é apenas uma questão de fazer uma comparação lexical:

awk '$2 < "2013/12/03"'
Stéphane Chazelas
fonte
2

Presumo que a <br>sua pergunta no final da datecoluna seja algo indesejável. Em qualquer caso, pode ser removido facilmente se estiver presente. No entanto, chegando à parte principal, você pode conseguir o que está tentando fazer usando,

sort -k 2n filename.txt

Agora, o comando acima daria a saída de maneira ordenada. Agora, o comando abaixo deve fornecer o que você procura.

sort -k 2n filename.txt | awk '/2013\/12\/03/ {exit} {print}' 

Explicação

O comando de classificação basicamente classifica o arquivo com base na segunda coluna, que é a data. Então, modifiquei seu arquivo de entrada para testar o comando se ele funciona, pois o arquivo de entrada tem todos os dados classificados por padrão. Depois disso, o awkcomando imprime todas as linhas até encontrarmos uma correspondência específica.

Teste

cat filename.txt

647919 2014/01/01
647946 2012/11/30
647955 2011/01/04
648266 2013/12/03
648267 2013/12/03
648674 2013/12/04

Agora, a sort -k 2n filename.txtsaída é,

647955 2011/01/04
647946 2012/11/30
648266 2013/12/03
648267 2013/12/03
648674 2013/12/04
647919 2014/01/01

Agora, estamos satisfeitos que o arquivo esteja classificado na segunda coluna. Agora, para selecionar valores UPTO uma data específica,

sort -k 2n filename.txt | awk '/2013\/12\/03/ {exit} {print}' 

No exemplo acima, eu recebo todos os valores 2013/12/03. A saída é,

647955 2011/01/04
647946 2012/11/30

Não, isso <br>faz parte do meu arquivo

Se for esse o caso, podemos ajustar um pouco o comando, como abaixo.

awk '{print $1, substr($2, 1, length($2)-4)}' filename.txt | 
sort -k 2n filename.txt | awk '/2013\/12\/03/ {exit} {print}' 

Estou apenas removendo todas as <br>tags da segunda coluna e canalizando o comando acima mencionado.

Referências

https://unix.stackexchange.com/a/11323/47538

https://unix.stackexchange.com/a/83069/47538

Ramesh
fonte
Obrigdo por sua contribuição. de fato, isso funciona muito, no entanto, a condição para sair nem sempre funciona quando a data específica não existe no arquivo.
Jason G
não, as tags br parecem ter sido adicionadas apenas para facilitar a leitura. Eles não podem ser vistos na primeira revisão
Braiam
-1

Solução rápida e suja para a data que você deu, basta excluir todas as linhas com sed, que correspondem a datas posteriores a esta data:

sed -i "" "#[0-9]* 2013/12/0[4-9]#d" testfile.txt
sed -i "" "#[0-9]* 2013/12/[123][0-9]#d" testfile.txt
sed -i "" "#[0-9]* 2014/[0-9][0-9]/[0-3][0-9]#d" testfile.txt

O -i "" está substituindo diretamente dentro do arquivo e não criando um backup, mas você também pode canalizar o arquivo de teste através de todos os 3 comandos sed sem o -i "".

Dependendo do seu sistema (linux ou mac), você pode omitir o "" depois de -i e às vezes precisa do parâmetro -e para as expressões regulares. Tenho que tentar o que funciona para você.

Pergunta relacionada com mais informações sobre sed: /programming/5410757/

toppy
fonte
#é o comando de comentáriosed , para que eles não façam nada. Use sed '\#patter#d'se você quiser um delimitador RE diferente de /. A [0-9]*peça é redundante sem uma ^âncora. -esó é necessário quando você deseja passar várias expressões. linux é um kernel, mac é uma marca de computador, nada tem a ver sed. A distinção é entre GNU sede FreeBSD sed(que OS / X (como encontrado em alguns macs) herdou).
Stéphane Chazelas