Comment supprimer certaines lignes (à l'aide de numéros de ligne) dans un fichier?


27

Il y a des lignes spécifiques que je veux supprimer d'un fichier. Disons que c'est la ligne 20-37, puis la ligne 45. Comment pourrais-je faire cela sans préciser le contenu de ces lignes?


Quelle est la taille de votre fichier? Pourrait-il être chargé en mémoire?
Faheem Mitha

Quelques kilo-octets.
tshepang

Réponses:


29

Avec sed, comme ça:

sed '20,37d; 45d' < input.txt > output.txt

Si vous vouliez le faire sur place:

sed --in-place '20,37d; 45d' file.txt

Existe-t-il un moyen de le faire sur place?
tshepang

Je suggère le fichier sed -i
enzotib

1
@Tshepang: Utilisez ed, ou GNU sed -i, ou sponge, ou une méthode de fichier volumineux .
Gilles 'SO- arrête d'être méchant'

3
Je me suis souvent posé des questions sur le terme éventuellement trompeur en place , quand je me référais à 'sed', donc je l'ai recherché dans 'man sed': --in-place [= SUFFIX]This option specifies that files are to be edited in-place. GNU sed 'le fait en créant un fichier temporaire et envoyer la sortie vers ce fichier plutôt que vers la sortie standard. »... Je ne connais pas d'autre« sed »mais la logistique de la mise à jour« en place »avec un éditeur de flux ne« calcule »pas :)
Peter.O

2
La plupart des méthodes "sur place" utilisent un fichier temporaire, d'après mon expérience.
Faheem Mitha

5

Si le fichier tient confortablement en mémoire, vous pouvez également l'utiliser ed.
Les commandes sont assez similaires à celle sedci-dessus avec une différence notable : vous devez passer la liste des numéros / plages de lignes à supprimer dans l'ordre décroissant (de la ligne / plage la plus élevée à la plus basse). La raison en est que lorsque vous supprimez / insérez / divisez / joignez des lignes avec ed, le tampon de texte est mis à jour après chaque sous-commande, donc si vous supprimez certaines lignes, les autres lignes suivantes ne seront plus à la même position dans le tampon lorsque le la sous-commande suivante est exécutée. Il faut donc recommencer à l'envers 1 .
Modification sur place :

ed -s in_file <<IN
45d
20,37d
w
q
IN

ou

ed -s in_file <<< $'45d\n20,37d\nw\nq\n'

ou

printf '%s\n' 45d 20,37d w q | ed -s in_file

Remplacez write par ,print si vous souhaitez imprimer la sortie résultante au lieu d'écrire dans un fichier. Si vous souhaitez conserver le fichier d'origine intact et écrire dans un autre fichier, vous pouvez passer le nouveau nom de fichier à la wsous-commande rite:

ed -s in_file <<IN
78,86d
65d
51d
20,37d
w out_file
q
IN

1 À moins que vous ne vouliez calculer les nouveaux numéros de ligne après chaque dsuppression, ce qui est assez trivial pour ce cas particulier (après la suppression des lignes 20 à 37, soit 18 lignes, la ligne 45 devient la ligne 27) afin que vous puissiez exécuter:

ed -s in_file <<IN
20,37d
27d
w
q
IN

Cependant, si vous devez supprimer plusieurs numéros de ligne / plages, travailler en arrière est une évidence.


La qcommande est-elle utile à la fin? Je suppose que ça sort de toute façon.
Tom Fenech

@ TomFenech - toutes les implémentations ne sortent pas dans les deux sens (bien que la plupart le fassent ... Je ne trouve plus le fil où cela a été discuté ...)
don_crissti

1

Il suffit de le lire en mémoire, de le modifier, puis de le réécrire. Vous pouvez faire quelque chose comme

filename = "foo"
f = open(filename, 'r+')                                                                                                                                 
linenums = [1, 3]                                                                                                                                            
s = [y for x, y in enumerate(f) if x not in [line-1 for line in linenums]]                                                                                                                                          
f.seek(0)
f.write(''.join(s))
f.truncate(f.tell())
f.close()

Testé avec un fichier 5 lignes. Crédits à http://pleac.sourceforge.net/pleac_python/fileaccess.html , voir la section "Modification d'un fichier sur place sans fichier temporaire". Voir aussi /programming/125703/how-do-i-modify-a-text-file-in-python

Quelques notes:

  1. On pourrait d'abord tronquer le fichier, puis y écrire, plutôt qu'écrire, puis tronquer, comme ci-dessus. Cependant, je ne connais pas d'indicateur Python qui permette de lire, puis de faire une écriture tronquée. Mais peut-être que je manque quelque chose, car le document n'est pas très clair. Ce qui m'amène à

  2. Parfois, les documents Python sont vraiment nuls. Voir http://docs.python.org/library/functions.html#open

    Les modes 'r +', 'w +' et 'a +' ouvrent le fichier pour la mise à jour (notez que 'w +' tronque le fichier).

    Est-ce que cela signifie quelque chose pour vous? Qu'est-ce qui est "ouvert à la mise à jour"?

  3. Je ne sais pas si faire cela en python par opposition à quelque chose d'unixy comme l'éditeur de flux est mieux. C'est peut-être plus portable, mais je ne sais pas à quel point sed est portable. Je viens de l'écrire comme ça parce que je suis plus à l'aise avec la programmation de bas niveau que d'utiliser les outils Unix classiques, qui sont bons s'ils font exactement ce que vous voulez, mais (je pense) sont généralement moins flexibles.

  4. Cette approche (manipulation du fichier en mémoire) échange la mémoire contre de l'espace disque. Cela devrait fonctionner correctement sur les machines avec quelques Go de mémoire pour des fichiers jusqu'à quelques centaines de Mb. Python ne gère pas les chaînes très efficacement, donc le passage au C / C ++ par exemple augmenterait légèrement les performances et réduirait considérablement l'utilisation de la mémoire.


0

Vous pouvez utiliser Vim en mode Ex:

ex -sc '20,37d|45d|x' file
  1. d supprimer

  2. x sauver et fermer

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.