Vim: comment supprimer une ligne sur deux?

99

Comment le faire dans Vim:

AVANT:

aaa
bbb
ccc
ddd
eee
fff

APRÈS:

aaa
ccc
eee
brazh
la source
Vous devriez pouvoir utiliser une macro: oreillynet.com/mac/blog/2006/07/…
Mark Wilkins
J'aime la richesse des réponses à celle-ci. Favoriser.
froggythefrog

Réponses:

105

Vous pouvez utiliser une macro pour cela. Procédez comme suit.

  • Démarrez en mode commande.
  • Aller au début du fichier en appuyant sur gg .
  • Appuyez sur qq.
  • Cliquez sur la flèche vers le bas et appuyez sur ddaprès.
  • Appuyez sur q.
  • presse 10000@q

PS: Pour passer en mode commande, appuyez simplement sur Echap plusieurs fois.

rui
la source
11
En supposant que votre fichier
comporte
3
En fait, vous vous trompez Michael. Cela fonctionne parfaitement car le VI arrêtera d'exécuter la macro dès qu'elle atteindra la fin du fichier. Vous pouvez très facilement l'essayer avec l'exemple ci-dessus.
rui
1
Eh bien, comme toute macro, vous devez faire les choses correctement la première fois, mais après cela, vous pouvez appliquer à n'importe quel fichier en tapant simplement 10000 @ q. Quoi qu'il en soit, je pense que c'est juste une question de goûts, donc je ne vais définitivement pas lancer un débat philosophique. :)
rui
3
Je préfère utiliser «macro». En utilisant la macro, vous «décrivez» comment vous résoudriez une tâche particulière et laissez VIM la répéter pour vous. RUI, je préférerais utiliser «j» au lieu de la touche fléchée.
SolutionYogi
4
:g/^/+dde l'utilisateur stackoverflow.com/users/254635/ib (ci-dessous) est un moyen plus élégant de résoudre ce problème.
SergioAraujo
254

Un moyen élégant (et efficace) d'accomplir la tâche consiste à appeler la :+deletecommande en supprimant la ligne qui suit la ligne actuelle, sur chaque ligne à l'aide de la :globalcommande:

:g/^/+d
ib.
la source
10
Pourquoi cette réponse n'a-t-elle pas reçu plus de votes? C'est tellement propre et simple. Vous pouvez également supprimer la première ligne et exécuter la commande ci-dessus pour supprimer toutes les lignes impaires.
Usagi
3
@Usagi: Merci! Je ressens la même chose à ce sujet. Et oui, vous avez tout à fait raison, :1d|g/^/+dsupprime les lignes impaires.
ib.
@Usagi L'autre réponse a été choisie comme «meilleure réponse» 2 ans avant que sa réponse n'apparaisse. De plus, bien que ce soit une solution plus élégante, elle aurait pu être écrite d'une manière plus utile (c'est-à-dire qu'il n'y a aucune mention de ce que fait ^, alors que la macro est facile à comprendre pour tout le monde).
user1271772
3
Désolé, mais sans une explication sur la façon dont cette commande exécute le comportement souhaité, je ne la voterais pas, et préférerais plutôt la réponse acceptée, car je comprends comment elle atteint l'objectif. C'est la différence entre donner un poisson à un homme et lui apprendre à pêcher.
Gabe
3
Je ne sais pas, cette réponse m'a fait sortir et apprendre à pêcher avec la commande: g (c'est-à-dire qu'elle m'a fait google cette page - vim.wikia.com/wiki/Power_of_g ).
snetch le
67

Nous pouvons utiliser :normalou :normexécuter des commandes de mode normal données. La source.

:%norm jdd
Tadhg
la source
15
Cette réponse ne retient pas suffisamment l'attention, peut-être à cause du manque d'explications à la fois ici et sur la feuille de triche liée et désordonnée. la commande norm exécute les commandes de mode normal équivalentes aux lettres qui la suivent. Donc, ici, il exécute j pour descendre d'une ligne et dd pour le supprimer. Ceci est généralisable à la Xème ligne en ajoutant plus de «j» dans ce cas.
imoatama
5
et le% est un raccourci pour 1, $ (exécutez la commande suivante de la ligne 1 à la fin)
Lambart
3
Je suis intéressé par pourquoi %norm ddjne fonctionne pas si vous souhaitez supprimer des lignes impaires.
Cyker
10
:map ^o ddj^o
^o

Ici ^ représente CTRL. Macro récursive pour supprimer une ligne toutes les deux lignes. Choisissez bien votre première ligne et c'est fait.

Raoul Supercoptère
la source
8

à partir de l' archive de messagerie vim :

:let i=1 | while i <= line('$') | if (i % 2) | exe i . "delete" | endif | let i += 1 | endwhile

(À taper sur une ligne de la ligne de commande vim, supprimera la ligne 1,3,5,7, ...)

Fortega
la source
4
Alors je préférerais !perl -ne 'print unless $. % 2':-)
Alex Brasetvik
Et, Alex, je préférerais définitivement ma solution à la vôtre, mais celle-ci mérite d'être prise en compte car c'est la seule solution sensée n'utilisant que vim lui-même ici.
Michael Krelin - hacker
La manière macro est tellement plus facile.
trusktr
+1 en raison de la flexibilité avec if (expression)laquelle fonctionne également pour chaque troisième ligne, etc.
Jens
5

Vous pouvez toujours exécuter une commande shell, ce qui signifie que vous pouvez utiliser n'importe quel langage de script que vous aimez:

:%!perl -nle 'print if $. % 2'

(ou utilisez "sauf" au lieu de "si", selon les lignes souhaitées)

svelte
la source
Vous n'avez pas besoin de -lpasser à Perl ... aussi, je dirais que awkc'est un peu plus répandu que Perl, bien que ce ne soit pas vraiment beaucoup plus de nos jours, et que vous puissiez le faire plus court:, :%!awk NR\%2ou :%!awk 1-NR\%2pour les autres lignes.
éphémient
4
:%!awk -- '++c\%2'

alternativement

:%!awk -- 'c++\%2'

selon la moitié que vous souhaitez éliminer.

Michael Krelin - hacker
la source
Euh, pourquoi ne pas utiliser la NRvariable existante ?
éphémère
Droite. Parce que je l'ai oublié. ;-) Mais en fait, la variante "appropriée" sera encore plus longue avec NR. Et il n'y aurait pas deux beaux homologues.
Michael Krelin - hacker
:%!awk NR\%2ou :%!awk 1-NR\%2, comme je l'ai posté dans un autre commentaire. Ce n'est guère plus long.
éphémient
1
1-NRest plus long que c++. Oui, je sais que c'est un personnage. Comme je l'ai dit, la vraie raison est que je l'ai oublié. Quoi qu'il en soit, on dirait que les gens n'apprécient pas la beauté de awk ici.
Michael Krelin - hacker
Et NRest plus court que ++c:)
éphémère
3

Vous pouvez utiliser les propres capacités de recherche et de substitution de Vim comme ceci: Placez votre curseur sur la première ligne et tapez en mode normal:

:.,/fff/s/\n.*\(\n.*\)/\1/g
  • Le .,/fff/est la plage pour la substitution. Cela signifie "de cette ligne à la ligne qui correspond à l'expression régulière fff(dans ce cas, la dernière ligne).
  • s///est la commande de substitution. Il recherche une expression régulière et remplace chaque occurrence de celle-ci par une chaîne. Le gà la fin signifie répéter la substitution tant que l'expression régulière continue d'être trouvée.
  • L'expression régulière \n.*\(\n.*\)correspond à une nouvelle ligne, puis à une ligne entière ( .*correspond à n'importe quel nombre de caractères à l'exception d'une nouvelle ligne), puis à une autre nouvelle ligne et une autre ligne. Les parenthèses \(et \)provoquent l'enregistrement de l'expression à l'intérieur, afin que nous puissions l'utiliser plus tard en utilisant\1 .
  • \1 insère la nouvelle ligne groupée et la ligne qui suit, car nous ne voulons pas que la ligne suivante disparaisse aussi - nous voulons juste que le mécanisme de substitution passe à côté afin de ne pas la supprimer dans le prochain remplacement.

De cette façon, vous pouvez contrôler la plage dans laquelle vous souhaitez que la suppression ait lieu et vous n'avez pas besoin d'utiliser d'outil externe.

Daniel Hershcovich
la source
Ou $au lieu de /fff/, pour la fin du fichier quel que soit le contenu du fichier.
éphémère
3

Comme autre approche, vous pouvez également utiliser python si votre vim le prend en charge.

:py import vim; cb = vim.current.buffer; b = cb[:]; cb[:] = b[::2]

b = cb[:]copie temporairement toutes les lignes de la mémoire tampon actuelle dans b. b[::2]récupère chaque deuxième ligne du tampon et l'assigne à l'ensemble du tampon courant cb[:]. La copie vers best nécessaire car les objets tampons ne semblent pas prendre en charge la syntaxe de tranche étendue.

Ce n'est probablement pas la "manière vim", mais cela pourrait être plus facile à retenir si vous connaissez python.

qzr
la source
2

Pour supprimer les lignes impaires (1,3,5, ..) -> :%s/\(.*\)\n\(.*\)\n/\2\r/g

Pour supprimer les lignes paires (2,4,6, ..) -> :%s/\(.*\)\n.*\n/\1\r/g

Recherchez du texte (forme la première ligne) suivi d'un caractère de nouvelle ligne et un peu plus de texte (forme la deuxième ligne) suivi d'un autre caractère de nouvelle ligne et remplacez ce qui précède par la première correspondance (ligne impaire) ou la deuxième correspondance (ligne paire) suivi d'un retour chariot.

kartik kailas
la source
0

Appelez sed:

:% !sed -e '2~2 d'

^^^^                  pipe file through a shell command
    ^^^^^^            the command is sed, and -e describes an expression as parameter
            ^^^^^     starting with the second line, delete every second line
asdmin
la source
-1

Solution

vous pouvez essayer ceci dans vim

:1,$-1g/^/+1d

Éditer

J'essaierai d'être plus clair (deux parties)

première partie la plage de sélection ( :from,to)
deuxième partie l'action ( dsupprimer)

  • la plage si de la première ligne à la dernière mais une ligne (:1,$-1 )
  • globaly ( g) delete ( +1d) ligne suivante

vous pouvez essayer de passer à la première ligne de votre fichier et exécuter :+1dvous verrez la ligne suivante disparaître

Je sais que c'est boueux, mais c'est vim et ça marche

wdog
la source
Clair comme de la boue. Merci!
Henry Henrinson le