5
votes

Supprimer les lignes en double uniquement si elles correspondent à un motif

Cette question a une excellente réponse disant que vous pouvez utiliser awk '! vu [$ 0] ++' file.txt pour supprimer les lignes en double non consécutives d'un fichier. Comment puis-je supprimer les lignes en double non consécutives d'un fichier uniquement si elles correspondent à un modèle? par exemple. uniquement s'ils contiennent la chaîne "#####"

Exemple d'entrée

deleteme.txt ##########
1219:                            'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1222:                          , 'PCM BE PTP UT'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
1223:                          , 'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
1225:                          , 'PCM FE/MID PTP'

Sortie souhaitée

deleteme.txt ##########
1219:                            'PCM BE PTP'
deleteme.txt ##########
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1222:                          , 'PCM BE PTP UT'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1223:                          , 'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1225:                          , 'PCM FE/MID PTP'

p >


4 commentaires

Veuillez ajouter un exemple d'entrée et la sortie souhaitée pour cet exemple d'entrée à votre question.


Et qu'avez-vous essayé aussi?


Assurez-vous que chaque question que vous postez a un sens de manière autonome et que le code que vous publiez dans votre question fournit un exemple reproductible minimal pour cette question spécifique, fournir un lien vers un code dans une autre réponse qui fait probablement plus que l'objet de votre question n'est pas la meilleure façon d'essayer d'amener les gens à vous aider.


Si vous obtenez votre fichier avec grep et après sed. Ajouter un awk à la fin n'est pas la meilleure façon. Tout peut être fait avec awk.


4 Réponses :


6
votes

Vous pouvez utiliser

deleteme.txt ##########
1219:                            'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1222:                          , 'PCM BE PTP UT'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
1223  #####:                          , 'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
1225:                          , 'PCM FE/MID PTP'

Ou, comme Ed Morton suggère , un synonyme

s="deleteme.txt ##########
1219:                            'PCM BE PTP'
deleteme.txt ##########
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1222:                          , 'PCM BE PTP UT'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1223  #####:                          , 'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1225:                          , 'PCM FE/MID PTP'"
awk '!/#####/ || !seen[$0]++' <<< "$s"

Ici, ! vu [$ 0] + + fait la même chose que d'habitude, il supprimera toute ligne dupliquée. La partie ! / ##### / correspond aux lignes qui contiennent un motif ##### et annule la correspondance. Les deux motifs combinés avec || supprimeront toutes les lignes dupliquées contenant un motif ##### .

Voir un démo en ligne awk :

awk '!(/#####/ && seen[$0]++)'

Résultat:

awk '!/#####/ || !seen[$0]++'


1 commentaires

J'ai voté pour cela parce qu'il fait exactement ce qui a été demandé et est plus simple que ma réponse.



0
votes

Chaque fois que je pense à la correspondance de motifs et à l'impression sélective, je pense au langage pratique d'extraction et de rapport: Perl! Voici un one-liner Perl qui fait ce que vous demandez. Vous devriez pouvoir copier-coller ceci dans un shell et le faire fonctionner:

BEGIN {
  # create a counter for rows that match the pattern
  $rows_with_five_hashes = {}; 
} 
# capture the row from the input file
$thisrow = $_;
if ($thisrow =~ /[#]{5}/) { 
  if (!exists $rows_with_five_hashes->{$thisrow}) { 
    # this row matches the pattern and we haven't seen it before
    print; 
  } 
  # Increment the counter for rows that match the pattern.
  # Do this AFTER we print, or else our "exists" print logic fails.
  $rows_with_five_hashes->{$thisrow}++;
} 
else { 
  # print all rows that don't match the pattern
  print;
}

Voici le même Perl avec des sauts de ligne et des commentaires pour plus de clarté (note: ce n'est pas exécutable tel quel / > Pour plus d'informations sur les commutateurs de ligne de commande wnle , consultez Documentation Perl à ce sujet . Si vous aviez de nombreux fichiers que vous souhaitiez modifier en place et conserver des copies de sauvegarde des originaux avec une seule commande Perl, consultez le commutateur -i dans ces documents. p>

Si vous vous retrouvez à exécuter ceci tout le temps et que vous souhaitez conserver un script exécutable à portée de main, vous pouvez l'adapter assez facilement pour qu'il fonctionne sur à peu près n'importe quel système doté d'un interpréteur Perl.


0 commentaires

2
votes

Essayez cette solution de regex en ligne de commande Perl en utilisant le mode file slurp.

$ cat toucan.txt
deleteme.txt ##########
1219:                            'PCM BE PTP'
deleteme.txt ##########
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1222:                          , 'PCM BE PTP UT'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1223:                          , 'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1225:                          , 'PCM FE/MID PTP'

$ perl -0777 -ne ' $z=$y=$_; while( $y ne $x) { $z=~s/(^[^\n]+?\s+##########.*?$)(.+?)\K(\1\n)//gmse ; $x=$y ;$y=$z } ; print "$z" ' toucan.txt
deleteme.txt ##########
1219:                            'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1222:                          , 'PCM BE PTP UT'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
1223:                          , 'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
1225:                          , 'PCM FE/MID PTP'

$

avec les entrées données

perl -0777 -ne ' $z=$y=$_; 
                 while( $y ne $x) 
                 { $z=~s/(^[^\n]+?\s+##########.*?$)(.+?)\K(\1\n)//gmse ; $x=$y ;$y=$z } ; 
                 print "$z" '


2 commentaires

++ Cela a l'air bien même si je préférerais awk par souci de simplicité


merci @ anubhava..oui, la solution awk est simple et directe .. J'essayais juste si une seule regex s /// le résoudrait.?.



0
votes

Cela pourrait fonctionner pour vous (GNU sed):

sed '/#$/{G;/^\(\S*\s\).*\1/!P;h;d}' file

Toutes les lignes autres que celles qui vous intéressent sont imprimées normalement.

Ajoutez les lignes d'intérêt précédentes au ligne courante et en utilisant la correspondance de motif, si une telle ligne n'a pas été rencontrée auparavant, imprimez-la. Ensuite, stockez l'espace de motif dans l'espace de maintien, prêt pour la prochaine correspondance et supprimez l'espace de motif.


0 commentaires