Comment supprimer une ligne sur deux d'un fichier?

25

Fichier:

Data inserted into table. Total count 13
No error occurred
Data inserted into table. Total count 45
No error occurred
Data inserted into table. Total count 14
No error occurred
Data inserted into table. Total count 90
No error occurred

Fichier de sortie attendu:

Data inserted into table. Total count 13
Data inserted into table. Total count 45
Data inserted into table. Total count 14
Data inserted into table. Total count 90

Je veux que la sortie ressemble à ceci: chaque seconde ligne sera supprimée mais il n'y aura pas d'espace entre les lignes.

pmaipmui
la source
5
Voulez-vous supprimer toutes les deux lignes ou toutes les lignes contenant "Aucune erreur ne s'est produite" ? Et si deux lignes consécutives avaient "Aucune erreur ne s'est produite" ?
Tulains Córdova
1
@ user1598390 Je pense ... dans ce cas, grep -v "No error occurred" filecette commande devrait fonctionner ... ce à quoi @paul a répondu. Dans le fichier de sortie, il n'y aura aucune ligne contenant "Aucune erreur ne s'est produite" dans cette partie.
pmaipmui
1
Le titre de la question est alors trompeur.
Tulains Córdova

Réponses:

36

Avec sed:

sed -e n\;d <file

Avec POSIX awk:

awk 'FNR%2' <file

Si vous avez plus awk(comme oawk), vous avez besoin de:

oawk 'NR%2 == 1' <file

Avec ex:

$ ex file <<\EX
:g/$/+d
:wq!
EX

éditera le fichier sur place.

  • g marquer une commande globale
  • /$/ correspondre à toutes les lignes
  • +d supprimer la ligne suivante
  • wq! Enregistrer toutes les modifications

Cette approche partage le même idéal avec l' sedapproche, supprimez chaque ligne suivante du début de la ligne actuelle de la ligne 1.

Avec perl:

perl -ne 'print if $. % 2' <file

et perl6:

perl6 -ne '.say if $*IN.ins % 2' <file
perl6 -ne '.say if ++$ % 2' <file
cuonglm
la source
Oui ... son fonctionnement ... :) ... le premier fonctionne .... j'ai également essayé le second ... il dit `awk: erreur de syntaxe line1 awk: renflouage près de la ligne 1 '
pmaipmui
sed -en \; d <file ~ Yes its working @cuonglm ...
pmaipmui
1
Je suppose que vous avez utilisé n\;dau lieu de 'n;d'sauvegarder un caractère précieux, mais cette logique sort de la fenêtre lorsque vous utilisez inutilement le -ecommutateur et une redirection de fichiers <!
Tom Fenech
1
@Geek: Ce n'est qu'une version plus courte de sed -e 'n;d', vous permet d'économiser un personnage.
cuonglm
1
@Geek: la ncommande écrit l'espace de motif sur la sortie standard si elle a -nété utilisée, puis remplacez l'espace de motif par la ligne suivante. Voici chaque ligne impaire sera imprimée par n, ligne paire puis lue dans l'espace de motif mais supprimez immédiatement par dcommande`.
cuonglm
62

Résoudre ce problème en supprimant toutes les deux lignes peut être source d'erreurs (par exemple, lorsque le processus génère parfois deux lignes significatives au lieu d'une). Il est peut-être préférable de filtrer les déchets:

grep -v "No error occurred" file

Il peut fonctionner comme un filtre, vous pouvez ajouter plus de modèles de déchets ici et améliorer le résultat.

Paul
la source
9
+1 pour avoir souligné que parfois la deuxième ligne est importante!
Kaz Wolfe
12

En réponse à la question, avec GNU sed:

sed '0~2d' file

supprimera toutes les deux lignes, mais j'aimerais proposer des lignes de filtrage par son contenu:

sed '/Data/! d' file

ou avec le même résultat

sed '/No error/d' file
Costas
la source
sed '/ No error / d' file ~ donne la sortie souhaitée @Costas
pmaipmui
5
Notez que les deux derniers sont des façons compliquées d'écrire grep Dataetgrep -v 'No error'
Stéphane Chazelas
5

Voici un moyen d'utiliser sed:

sed -n 'p;n' filename

Une autre façon avec GNU sed:

sed -n '1~2p' filename

Sortie des commandes ci-dessus:

Data inserted into table. Total count 13
Data inserted into table. Total count 45
Data inserted into table. Total count 14
Data inserted into table. Total count 90
serenesat
la source
Que voulez-vous dire en disant shortest way using sed?
cuonglm
Quelle est la raison de la gcommande? sed -n 'p;n'est assez.
Costas
@cuonglm: Je veux dire une façon simple de faire. Soit dit en passant, a supprimé ce mot. :)
serenesat
@Costas: Merci! Je viens de vérifier, ça fonctionne sans g. supprimé g de la commande. :)
serenesat
4

Vous pouvez essayer avec awk:

awk 'NR % 2 != 0' file

ou vous ne pouvez imprimer que des lignes contenant Data inserted:

awk '$0 ~ /Data inserted/' file
taliezin
la source
J'ai essayé les deux réponses et les deux fonctionnent ... :)
pmaipmui
3

Une autre réponse, vous pouvez utiliser vi / vim!

qdjddq

Et puis si votre fichier était de 500 lignes (par exemple) tapez

250 @ d

Et puis pour écrire et quitter le type

:X

Ou si quelque chose ne va pas et que vous ne souhaitez pas enregistrer:

: q!

Explication:

q      #Start Recording
 d     #Put the recording into register 'd'
  j    #Move the cursor down
   dd  #Delete the line
     q #Stop recording


250    #Number of repeats
   @d  #Playback the recording in register 'd'.
DJMcMayhem
la source
2

Voici une façon très différente de procéder:

< file paste - - | cut -f1

Cela suppose que les lignes impaires ne contiennent pas de tabulations. Si c'est le cas, vous devrez choisir un autre caractère séparateur, par exemple :ici:

< file paste -d: - - | cut -d: -f1
Traumatisme numérique
la source
1
J'avais cela en tête quand j'ai vu la question pour la première fois ... Ce serait intéressant de faire un test de vitesse sedavec un fichier énorme (par exemple 20 lignes mil). Quoi qu'il en soit, +1 mais vraiment, pour éviter les maux de tête, choisissez un délimiteur qui ne se produira probablement pas dans un fichier texte, comme $'\002'...
don_crissti
@don_crissti oui l'utilisation d'un caractère non imprimable pour le séparateur est une bonne idée. Et oui, c'est beaucoup plus rapide que la solution sed. J'ai créé un fichier de test avec seq 100000000 > 100mil.txt. La paste|cutsolution s'est terminée en environ 7,5 secondes, contre près de 12 pour la sedsolution. Semble être reproductible. grepest le plus rapide. Ubuntu 14.04 avec des outils GNU standard.
Digital Trauma
Oui, paste+ cutsont fortement optimisés pour leur travail, alors sans surprise, leur combinaison est sacrément rapide ...
don_crissti
1

Une autre option (plus courte)

sed 'n; d' file
Michael Durrant
la source
3
C'est plus long que le mien sed n\;d, l'ajout -en'est que mon habitude.
cuonglm
0

Cela résout également le problème, bien qu'il soit un peu plus lent:

vim -c "%normal jdd" -c "wq" file
FloriOn
la source