web-dev-qa-db-fra.com

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

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

211
Justin Ethier

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 jusqu'à file.bak et supprimera les lignes données.

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

336
Brian Campbell

Vous pouvez supprimer une ligne particulière avec son numéro de ligne par fichier sed -i '33d'

Ceci supprimera la ligne sur le numéro de ligne 33 et sauvegardera le fichier mis à jour.

40
amit

et awk aussi

awk 'NR!~/^(5|10|25)$/' file
25
ghostdog74
$ cat foo
1
2
3
4
5
$ sed -e '2d;4d' foo
1
3
5
$ 
16
Matthew Slattery

C'est très souvent le symptôme d'un antipattern. L'outil qui a généré les numéros de ligne peut très bien être remplacé par un outil qui supprime immédiatement les lignes. Par exemple;

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

(où deletelines est l’utilitaire dont vous imaginez avoir besoin) est identique à

grep -v error logfile

Cela dit, si vous vous trouvez dans une situation où vous devez réellement exécuter cette tâche, vous pouvez générer un simple script sed à partir du fichier de numéros de ligne. Avec humour (mais peut-être légèrement déroutant), vous pouvez le faire avec sed.

sed 's%$%d%' linenumbers

Ceci accepte un fichier de numéros de ligne, un par ligne, et produit, sur une sortie standard, les mêmes numéros de ligne, suivis de d. Ceci est un script valide sed, que nous pouvons enregistrer dans un fichier ou (sur certaines plates-formes) diriger vers un autre exemple sed:

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

Sur certaines plates-formes, sed -f ne comprend pas que l'argument d'option - signifie une entrée standard. Vous devez donc rediriger le script vers un fichier temporaire et le nettoyer lorsque vous avez terminé, ou éventuellement remplacer le seul tiret avec /dev/stdin ou /proc/$pid/fd/1 si votre système d'exploitation (ou votre shell) en est équipé.

Comme toujours, vous pouvez ajouter -i avant l'option -f pour que sed modifie le fichier cible à la place, au lieu de produire le résultat sur une sortie standard. Sur les plates-formes * BSDish (y compris OSX), vous devez également fournir un argument explicite pour -i; un langage courant consiste à fournir un argument vide; -i ''.

6
tripleee

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

Lorsque le fichier est créé par blocs de taille fixe et que les lignes à supprimer sont répétées pour chaque bloc, awk peut fonctionner correctement.

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 souhaite 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)+1 Ici, nous écrivons dans la variable nl le numéro de ligne à l'intérieur du bloc actuel. (voir ci-dessous)
  • || et && sont l'opérateur logique OU et ET.
  • 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      |
+-----+------+----------+------------+

2
Hastur