supprimer des lignes plus récentes que la date indiquée dans un fichier

8

Je suis bloqué sur la façon de supprimer les lignes plus récentes que la date indiquée. Voici un extrait du contenu d'un fichier.

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

Je voudrais supprimer les lignes plus récentes que le 03/12/2013 en ne laissant que

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

Comment cela peut-il se faire via bash?

Jason G
la source

Réponses:

4

Si votre système inclut la version GNU de la datecommande, vous pouvez l'utiliser pour convertir le champ de date (après suppression de la fin <br>, le cas échéant) en secondes depuis l'époque et comparer directement à la date de coupure dans le même format, par exemple en 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

[Notez que cela n'effectue pas de suppression sur place - vous devez enregistrer les résultats dans un fichier temporaire et renommer.]

tournevis
la source
Vous monsieur m'a sauvé un mal de tête. Ceci est exactement ce que je cherchais!
Jason G
beurk! Ces dates trient le même lexicographiquement et chronologiquement, il n'est pas nécessaire de les convertir en entier et d'exécuter 5 commandes, de créer un fichier temporaire et deux tubes par ligne!
Stéphane Chazelas
9

Ces dates trient le même lexicographiquement et chronologiquement, il ne s'agit donc que de faire une comparaison lexicale:

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

Je suppose que le <br>dans votre question à la fin de la datecolonne est quelque chose de indésirable. Dans tous les cas, il peut être retiré facilement s'il est présent. Cependant, en venant à la partie principale, vous pouvez réaliser ce que vous essayez de faire en utilisant,

sort -k 2n filename.txt

Maintenant, la commande ci-dessus donnerait la sortie d'une manière triée. Maintenant, la commande ci-dessous devrait donner ce que vous recherchez.

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

Explication

La commande sort trie essentiellement le fichier en fonction de la deuxième colonne qui est la date. J'ai donc modifié votre fichier d'entrée pour tester la commande si elle fonctionne puisque le fichier d'entrée a toutes les données triées par défaut. Après cela, la awkcommande imprime toutes les lignes jusqu'à ce que nous rencontrions une correspondance particulière.

Essai

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

Maintenant, la sort -k 2n filename.txtsortie est,

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

Nous sommes maintenant convaincus que le fichier est trié sur la deuxième colonne. Maintenant, pour sélectionner des valeurs JUSQU'À une date particulière,

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

Dans l'exemple ci-dessus, j'obtiens toutes les valeurs jusqu'à 2013/12/03. La sortie est,

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

Non, <br>ça fait partie de mon dossier

Si tel est le cas, nous pouvons modifier légèrement la commande comme ci-dessous.

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

Je supprime donc toutes les <br>balises de la deuxième colonne, puis je passe la commande mentionnée ci-dessus.

Références

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

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

Ramesh
la source
Merci pour votre participation. cela fonctionne en effet considérablement cependant, la condition de sortie ne fonctionne pas toujours lorsque la date spécifique n'existe pas dans le fichier.
Jason G
non, les balises br semblent avoir été ajoutées juste pour rendre la chose lisible. Ils ne peuvent pas être vus dans la première révision
Braiam
-1

Solution rapide et sale pour la seule date que vous avez donnée, supprimez simplement toutes les lignes avec sed, qui correspondent à des dates postérieures à cette date:

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

Le -i "" remplace directement l'intérieur du fichier et ne crée pas de sauvegarde, mais vous pouvez également diriger le fichier de test via les 3 commandes sed sans le -i "".

En fonction de votre système (linux ou mac), vous pouvez annuler le "" après -i et parfois vous avez besoin du paramètre -e pour les expressions régulières. Je dois essayer ce qui fonctionne pour vous.

Question connexe avec plus d'informations sur sed: /programming/5410757/

toppy
la source
#est la commande commentsed , donc ceux-ci ne feront rien. Utilisez sed '\#patter#d'si vous souhaitez un délimiteur RE différent de /. La [0-9]*pièce est redondante sans ^ancrage. -en'est nécessaire que lorsque vous souhaitez transmettre plusieurs expressions. linux est un noyau, mac est une marque informatique, aucun n'a rien à voir avec sed. La distinction est entre GNU sedet FreeBSD sed(dont OS / X (comme sur certains macs) ont hérité).
Stéphane Chazelas