Supprimer le numéro de ligne spécifique (s) à partir d'un fichier texte en utilisant sed?
-
22-09-2019 - |
Question
Je veux supprimer un ou plusieurs numéros de ligne spécifiques à partir d'un fichier. Comment puis-je faire cela en utilisant sed?
La solution
Si vous voulez supprimer des lignes 5 à 10 et 12:
sed -e '5,10d;12d' file
Cela affichera 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
Ceci sauvegardera le fichier jusqu'à file.bak
et supprimer les lignes données.
Remarque: Les numéros de ligne commencent à 1. La première ligne du fichier est 1, de 0
.Autres conseils
Vous pouvez supprimer une seule ligne particulière avec son numéro de ligne par sed -i fichier '33d'
Ceci supprimera la ligne 33 sur le numéro de ligne et enregistrez le fichier mis à jour.
et awk ainsi
awk 'NR!~/^(5|10|25)$/' file
$ cat foo
1
2
3
4
5
$ sed -e '2d;4d' foo
1
3
5
$
Ceci est très souvent un symptôme d'un antimodèle. L'outil qui a produit les numéros de ligne pourrait bien être remplacé par un qui supprime les lignes tout de suite. Par exemple;
grep -nh error logfile | cut -d: -f1 | deletelines logfile
(où deletelines
est l'utilitaire que vous vous imaginiez besoin) est le même que
grep -v error logfile
Cela dit, si vous êtes dans une situation où vous avez vraiment besoin pour effectuer cette tâche, vous pouvez générer un simple script sed
à partir du fichier des numéros de ligne. Humoristiquement (mais peut-être un peu prêter à confusion), vous pouvez le faire avec sed
.
sed 's%$%d%' linenumbers
accepte un fichier de numéros de ligne, une par ligne, et produit, sur la sortie standard, les mêmes numéros de ligne avec d
ajoutés après chaque. Ceci est un script sed
valide, que nous pouvons enregistrer dans un fichier, ou (sur certaines plates-formes) conduit à une autre instance sed
:
sed 's%$%d%' linenumbers | sed -f - logfile
Sur certaines plateformes, sed -f
ne comprend pas l'argument de l'option -
signifie l'entrée standard, donc vous devez rediriger le script dans un fichier temporaire, et nettoyez-le lorsque vous avez terminé, ou remplacer peut-être le tableau de bord seul avec /dev/stdin
ou /proc/$pid/fd/1
si votre système d'exploitation (ou shell) a cela.
Comme toujours, vous pouvez ajouter -i
avant l'option d'avoir -f
sed
modifier le fichier cible en place, au lieu de produire le résultat sur la sortie standard. Sur les plates-formes * BSDish (y compris Mac OS X), vous devez fournir un argument explicite à -i
ainsi; un idiome commun est de fournir un argument vide; -i ''
.
Je voudrais proposer une généralisation avec awk.
Lorsque le fichier est effectuée par blocs de taille fixe et les lignes à supprimer sont répétées pour chaque bloc, awk peut fonctionner correctement de 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 la ligne actuelle. -
%
donne le reste (ou module) de la division de deux nombres entiers; -
nl=((NR-1)%BLOCKSIZE)+1
nous écrivons ici dans la variable nl le numéro de ligne à l'intérieur du bloc en cours. (Voir ci-dessous) -
||
et&&
sont l'opérateur logique ou 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 |
+-----+------+----------+------------+