Supprimer des numéros de ligne spécifiques d'un fichier texte à l'aide de sed?

235

Je souhaite supprimer un ou plusieurs numéros de ligne spécifiques d'un fichier. Comment pourrais-je faire cela en utilisant sed?

Justin Ethier
la source
1
Pouvez-vous donner un exemple plus précis de ce que vous voulez? Comment déciderez-vous quelles lignes supprimer?
Mark Byers
Voir peut-être aussi stackoverflow.com/questions/13272717/… et juste l'appliquer à l'envers (imprimer si la clé n'est pas dans le tableau associatif).
tripleee

Réponses:

374

Si vous souhaitez supprimer les lignes 5 à 10 et 12:

sed -e '5,10d;12d' file

Cela imprimera les résultats à l'écran. Si vous souhaitez enregistrer les résultats dans le même fichier:

sed -i.bak -e '5,10d;12d' file

Cela sauvegardera le fichier file.baket supprimera les lignes données.

Remarque: les numéros de ligne commencent à 1. La première ligne du fichier est 1, pas 0.

Brian Campbell
la source
32
Tous les unix n'ont pas gnu sed avec "-i". Ne faites pas l'erreur de retomber sur "sed cmd file> file", qui effacera votre fichier.
pra
4
Et si je voulais supprimer la 5ème ligne jusqu'à la dernière ligne?
Jürgen Paul
14
@WearetheWorldsed -e '5,$d' file
Brian Campbell
1
@BrianCampbell Que dois-je faire pour supprimer uniquement une ligne particulière ??
Kanagavelu Sugumar
14
@KanagaveluSugumar sed -e '5d' file. La syntaxe est <address><command>; où <address>peut être soit une seule ligne, 5soit une plage de lignes 5,10, et la commande dsupprime la ou les lignes données. Les adresses peuvent également être des expressions régulières ou le signe dollar $indiquant la dernière ligne du fichier.
Brian Campbell du
50

Vous pouvez supprimer une seule ligne particulière avec son numéro de ligne en

sed -i '33d' file

Cela supprimera la ligne sur le numéro de 33 lignes et enregistrera le fichier mis à jour.

amit
la source
1
Dans mon cas, "sed" a supprimé une mauvaise ligne. Donc j'utilise cette approche: sed -i '0,/<TARGET>/{/<NEW_VALUE>/d;}' '<SOME_FILE_NAME>'. Merci!
Eduardo Lucio
De même ici, j'ai écrit une boucle et étrangement certains fichiers ont perdu la ligne correcte mais certains fichiers ont également perdu une autre ligne, je n'ai aucune idée de ce qui s'est passé. (GNU / Linux bash4.2) La commande awk ci-dessous a bien fonctionné en boucle
FatihSarigol
Faites très attention à utiliser sort -r si vous supprimez d'une liste de lignes, sinon votre premier sed changera les numéros de ligne de tout le reste! ...
Konchog
Aux commentaires sur les mauvaises lignes supprimées dans une boucle: assurez-vous de commencer par le plus grand numéro de ligne, sinon chaque ligne supprimée compensera la numérotation des lignes…
Skippy le Grand Gourou
25

et awk aussi

awk 'NR!~/^(5|10|25)$/' file
ghostdog74
la source
2
NB: Cette ligne awk a fonctionné de manière plus fiable pour moi que la variante sed (entre OS-X et Ubuntu Linux)
Jay Taylor
3
Notez que cela ne supprime rien dans le fichier. Il imprime simplement le fichier sans ces lignes sur stdout. Vous devez donc également rediriger la sortie vers un fichier temporaire, puis déplacer le fichier temporaire pour remplacer l'original.
mivk
17
$ cat foo
1
2
3
4
5
$ sed -e '2d;4d' foo
1
3
5
$ 
Matthew Slattery
la source
6

Il s'agit très souvent d'un symptôme d'antipattern. L'outil qui a produit les numéros de ligne pourrait bien être remplacé par un outil qui supprime immédiatement les lignes. Par exemple;

grep -nh error logfile | cut -d: -f1 | deletelines logfile

(où deletelinesest l'utilitaire dont vous pensez avoir besoin) est le même que

grep -v error logfile

Cela dit, si vous êtes dans une situation où vous devez vraiment effectuer cette tâche, vous pouvez générer un sedscript simple à partir du fichier de numéros de ligne. Avec humour (mais peut-être un peu confus), vous pouvez le faire avec sed.

sed 's%$%d%' linenumbers

Cela accepte un fichier de numéros de ligne, un par ligne, et produit, sur la sortie standard, les mêmes numéros de ligne avec en dannexe après chacun. Il s'agit d'un sedscript valide , que nous pouvons enregistrer dans un fichier ou (sur certaines plates-formes) diriger vers une autre sedinstance:

sed 's%$%d%' linenumbers | sed -f - logfile

Sur certaines plates-formes, sed -fne comprend pas l'argument option -pour signifier une entrée standard, vous devez donc rediriger le script vers un fichier temporaire et le nettoyer lorsque vous avez terminé, ou peut-être remplacer le tiret isolé par /dev/stdinou /proc/$pid/fd/1si votre système d'exploitation (ou shell ) a cela.

Comme toujours, vous pouvez ajouter -iavant l' -foption de sedmodifier le fichier cible en place, au lieu de produire le résultat sur la sortie standard. Sur les plates-formes * BSDish (y compris OSX), vous devez également fournir un argument explicite -i; un idiome courant consiste à fournir un argument vide; -i ''.

tripleee
la source
Je ne suis pas tout à fait d'accord avec "symptôme d'un contre-modèle". Les types de fichiers basés sur le balisage (par exemple XML ou JSON) nécessitent des lignes spécifiques à la fin pour être des fichiers valides. Dans ce cas, c'est souvent l'approche la plus raisonnable pour supprimer ces lignes, mettre dans le fichier ce que vous voulez ajouter, puis rajouter ces lignes, car mettre les lignes entre les deux peut être beaucoup plus difficile, et va à l'encontre de le désir potentiel d'éviter autant que possible des outils supplémentaires comme sed.
Egor Hans
Je ne comprends pas très bien quel genre de scénario vous imaginez. Il y a des scénarios où c'est une approche légitime mais la grande majorité des cas que j'ai vus sont des débutants qui font plus ou moins exactement ce que mon premier exemple démontre. (Peut-être qu'ils proviennent d'un langage de très bas niveau et sont habitués à diviser leur problème bien au-delà du niveau moléculaire, parce que vous devez le faire en asm ou en C.)
tripleee
La suppression de trucs par numéro de ligne de XML ou JSON semble extrêmement fragile, sinon carrément dangereuse.
tripleee
Ce que je veux dire par là, c'est qu'en tant que créateur d'un tel fichier, vous savez ce qui doit être à la fin du document (c'est-à-dire l'ensemble des accolades de fermeture / crochets dans les dernières lignes pour JSON, ou l'exact fermeture des balises pour XML). En étant conscient de cela, l'approche la plus simple pour étendre un tel document est 1) supprimer les dernières lignes, 2) ajouter le nouveau contenu, 3) rajouter les dernières lignes. De cette façon, le document peut être valide avant et après son extension, sans avoir besoin de trouver un moyen d'ajouter des lignes au milieu du document.
Egor Hans
1
Jusqu'à présent, c'est la seule réponse avec une solution appropriée pour un grand nombre de lignes (c'est-à-dire fournie par un fichier). Et la préface est également logique. Il mérite plus de votes positifs. BTW, si vous souhaitez imprimer des lignes plutôt que de les supprimer, utilisez pau lieu de d, avec option -n(cela ne fonctionnera pas sans -net !dne fonctionnera pas non plus).
Skippy le Grand Gourou
2

Je voudrais proposer une généralisation avec awk.

Lorsque le fichier est constitué de blocs de taille fixe et que les lignes à supprimer sont répétées pour chaque bloc, awk peut fonctionner correctement de cette manière

awk '{nl=((NR-1)%2000)+1; if ( (nl<714) || ((nl>1025)&&(nl<1029)) ) print  $0}'
 OriginFile.dat > MyOutputCuttedFile.dat

Dans cet exemple, la taille du bloc est 2000 et je veux imprimer les lignes [1..713] et [1026..1029].

  • NR est la variable utilisée par awk pour stocker le numéro de ligne actuel.
  • % donne le reste (ou module) de la division de deux entiers;
  • nl=((NR-1)%BLOCKSIZE)+1Ici, nous écrivons dans la variable nl le numéro de ligne à l'intérieur du bloc courant. (voir ci-dessous)
  • ||et &&sont l'opérateur logique OR et AND .
  • print $0 écrit la ligne complète

Why ((NR-1)%BLOCKSIZE)+1:
(NR-1) We need a shift of one because 1%3=1, 2%3=2, but 3%3=0.
  +1   We add again 1 because we want to restore the desired order.

+-----+------+----------+------------+
| NR  | NR%3 | (NR-1)%3 | (NR-1)%3+1 |
+-----+------+----------+------------+
|  1  |  1   |    0     |     1      |
|  2  |  2   |    1     |     2      |
|  3  |  0   |    2     |     3      |
|  4  |  1   |    0     |     1      |
+-----+------+----------+------------+

Hastur
la source
2
J'admire la façon dont vous vivez votre nom inducteur de folie.
Jukka Dahlbom