Supprimer les lignes qui ne commencent pas par un motif d'un ensemble donné de motifs

11

J'ai un fichier qui contient des données comme celle-ci:

report aaaaaaaa  
-  ..  
-th bbbbbbbbb  
-to ccccccccc

.. --.

Question: Je souhaite supprimer toute ligne qui ne commence pas par les chaînes suivantes:

report  
-th  
-to

cela signifie que la sortie désirée supprimera tous ces points et hachages indésirables du milieu et ressemblera à ceci:

report aaaaaaaa  
-th bbbbbbbbb  
-to ccccccccc

sed/ awk/ grep/ etc toute solution qui fonctionnera.

Rana Khan
la source

Réponses:

15

Utiliser sedpour modifier le fichier en place:

sed -i '/^\(report\|-t\(h\|o\)\)/!d' your_file

Cela demande sedde supprimer toutes les lignes ne correspondant pas au modèle. Le motif lui-même est ^(début de ligne), suivi de l'un reportou -tde l'autre hou de ou o.

Vous devez noter que ce n'est pas une modification réelle sur place: sedcrée une copie de sauvegarde temporaire et écrase le fichier d'origine avec.

Si vous souhaitez sedconserver une copie de sauvegarde du fichier d'origine (ce qui peut être une bonne idée si le fichier contient des données critiques), donnez au -icommutateur une extension pour créer un fichier de sauvegarde:

sed -i'.bak' -e '/^\(report\|-t\(h\|o\)\)/!d' your_file

va modifier your_fileet créer une sauvegarde de l'original appelé your_file.bak.

Une note latérale

Veuillez ne pas mal interpréter mes intentions ou m'en offusquer, mais j'ai remarqué que vous avez de nombreuses questions similaires liées à l'expression rationnelle / au traitement de texte. Je vous conseille de commencer à apprendre sed, awket greppar vous-même pour accélérer votre productivité. Encore une fois, ne vous méprenez pas, je suis trop heureux d'aider (comme la plupart des gens ici); c'est juste que je pense que vous bénéficierez énormément de ramasser ces outils pour votre usage quotidien.

Juste pour prouver à quel point les gens sont utiles ici, tenez compte de la suggestion de @ slm dans les commentaires ci-dessous et n'hésitez pas à visiter ce salon de discussion à tout moment pour des questions.

Joseph R.
la source
1
Votre expression régulière semble inutilement cryptique. Je pense que vous utilisez en fait plus de caractères que si vous veniez de lister explicitement les trois options.
nispio
1
@nispio Je sais, mais il sera probablement plus efficace si le fichier en question est volumineux.
Joseph R.
Intéressant. J'ai toujours mesuré les expressions régulières en termes de longueur ou de lisibilité. Je n'ai jamais beaucoup réfléchi à la vitesse d'exécution. Je ne pense pas en savoir assez sur la façon dont ils sont évalués pour juger de ce qui est rapide, mais je suppose que c'est aussi spécifique à l'implémentation, non?
nispio
3
En réitérant ce que Joseph a dit à propos de sa volonté d'aider, si vous avez des questions générales qui ne correspondent pas au style Q&R, vous pouvez toujours essayer de nous parler dans la salle de chat de ce site. chat.stackexchange.com/rooms/26/unix-and-linux . Nous sommes plusieurs à y vivre 8-)
slm
@slm Merci pour cela. Je vais l'ajouter à ma réponse.
Joseph R.
10

Vous pouvez utiliser un simple grep pour cela:

$ grep -e '^report\|^-th\|^-to' filename
pradeepchhetri
la source
1
Ce n'est pas beaucoup d'économies, mais vous pouvez combiner le -th/ -todans -t[ho].
Kevin
grep -eouegrep
Olivier Dulac
2

En utilisant sed:

sed -n -e '/^report\|^-th\|^-to/p' filename
nispio
la source
Ce n'est pas beaucoup d'économies, mais vous pouvez combiner le -th/ -todans -t[ho].
Kevin
1
@Kevin C'est vrai. Voir ma conversation avec Joseph R. dans les commentaires de sa réponse.
nispio
2

En utilisant awk:

awk '/^report|^-t[ho]/' file
jasonwryan
la source
Ce n'est pas beaucoup d'économies, mais vous pouvez combiner le -th/ -todans -t[ho].
Kevin
1

L'intervenant a soulevé deux points:

  • vouloir supprimer toute ligne ne commençant pas par "report" ou "-th" ou "-to".
  • la sortie souhaitée devrait supprimer "tous ces points et hachages indésirables du milieu (sic)"

Les solutions, à l'heure actuelle, abordent le premier point et donc aussi le second. Mais supposons que le fichier soit plus grand et ressemble à:

report aaaaaaaa  
-  ..  
-th bbbbbbbbb  
-to ccccccccc
anything else
.. --.
-tp ddd
-tq eee
     -  -----

Le deuxième point d'OP ne répondrait-il pas aux besoins?

sed -r -i.bak '/^[ |.|-]*$/d' input-file 

fait le travail de supprimer les lignes vraisemblablement indésirables contenant uniquement des espaces, des points et des tirets et de conserver le reste, quel qu'il soit.
Je pense que le risque de l'une ou l'autre approche est que la nature du fichier n'est pas correctement définie.


la source
0

Utilisation de Perl:

perl -ne 'print if /^report|^-t[ho]/' filename > newfile

ou, pour éditer sur place (comme sed, perlfera également une sauvegarde temporaire donc ce n'est pas vrai sur place ):

perl -i.bak -ne 'print if /^report|^-t[ho]/' filename

Cela fera une copie du fichier d'origine appelé filename.baket écrasera votre fichier d'origine avec la version modifiée.

terdon
la source