Comment utiliser sed pour supprimer les n dernières lignes d'un fichier


148

Je veux supprimer quelques n lignes de la fin d'un fichier. Cela peut-il être fait en utilisant sed?

Par exemple, pour supprimer les lignes de 2 à 4, je peux utiliser

$ sed '2,4d' file

Mais je ne connais pas les numéros de ligne. Je peux supprimer la dernière ligne en utilisant

$sed $d file

mais je veux savoir comment supprimer n lignes de la fin. S'il vous plaît laissez-moi savoir comment faire cela en utilisant sed ou une autre méthode.


2
@arashkordi: qui utilise un nombre de lignes à partir du haut du fichier, pas du bas.
ams

Question connexe sur les super-utilisateurs .
Thor

//, Peut-être envisager de reformuler la question pour la rendre plus générale que juste sed ?
Nathan Basanese le

1
sed $d filerenvoie une erreur. Au lieu de cela, $ d devrait être entre guillemets, comme ceci:sed '$d' file
Akronix

Réponses:


221

Je ne sais pas sed, mais cela peut être fait avec head:

head -n -2 myfile.txt

19
+1 pour la simplicité. La commande sed équivalente est moche: sed -e :a -e '$d;N;2,5ba' -e 'P;D' file( ,5pour les 5 dernières lignes).
Marc B

62
Notez que cela fonctionne avec certaines versions de head, mais n'est pas standard. En effet, la norme pour les headétats:The application shall ensure that the number option-argument is a positive decimal integer.
William Pursell

21
Pour ajouter à la réponse de @ WilliamPursell ... Sur le shell par défaut de Mac OS, cela ne fonctionne pas.
JDS

7
Ni sur BSD, mais la question est étiquetée Linux.
ams le

3
moins 1, car, en plus d'osx, cela ne fonctionne pas pour moi sur Ubuntu14 -head: illegal line count -- -2
Michael Durrant

30

Si le codage en dur n est une option, vous pouvez utiliser des appels séquentiels à sed. Par exemple, pour supprimer les trois dernières lignes, supprimez la dernière ligne trois fois:

sed '$d' file | sed '$d' | sed '$d'

2
Ceci, plus -i pour éditer le fichier sur place plutôt que de le vider vers stdout, a fonctionné pour moi.
WAF

27

Des one-liners sed :

# delete the last 10 lines of a file
sed -e :a -e '$d;N;2,10ba' -e 'P;D'   # method 1
sed -n -e :a -e '1,10!{P;N;D;};N;ba'  # method 2

Semble être ce que vous recherchez.


@Thor, vous pouvez modifier le nombre de lignes supprimées du fichier en modifiant le 10in'$d;N;2,10ba'
Alexej Magura

1
@AlexejMagura: Je commentais une version antérieure de la réponse.
Thor

22

Un drôle et simple , sedet tacsolution:

n=4
tac file.txt | sed "1,$n{d}" | tac

REMARQUE

  • des guillemets doubles "sont nécessaires pour que le shell évalue la $nvariable dans la sedcommande. Entre guillemets simples, aucune interpolation ne sera effectuée.
  • tacest un catinversé, voirman 1 tac
  • les {}in sedsont là pour séparer $n& d(sinon, le shell essaie d'interpoler une $ndvariable inexistante )

7
fyi no tacon osx
Michael Durrant

1
@MichaelDurrant port info coreutils|| brew info coreutils;
voix du

19

Utilisez sed, mais laissez le shell faire le calcul, le but étant d'utiliser la dcommande en donnant une plage (pour supprimer les 23 dernières lignes):

sed -i "$(($(wc -l < file)-22)),\$d" file

Pour supprimer les 3 dernières lignes, de l'intérieur vers l'extérieur:

$(wc -l < file)

Donne le nombre de lignes du fichier: dis 2196

Nous voulons supprimer les 23 dernières lignes, donc pour le côté gauche ou la plage:

$((2196-22))

Donne: 2174 Ainsi, le sed original après l'interprétation de la coque est:

sed -i '2174,$d' file

Avec -ila modification sur place, le fichier est maintenant 2173 lignes!

Si vous souhaitez l'enregistrer dans un nouveau fichier, le code est:

sed -i '2174,$d' file > outputfile

15

Vous pouvez utiliser la tête pour cela.

Utilisation

$ head --lines=-N file > new_file

où N est le nombre de lignes que vous souhaitez supprimer du fichier.

Le contenu du fichier d'origine moins les N dernières lignes sont maintenant dans new_file


8

Par souci d'exhaustivité, j'aimerais ajouter ma solution. J'ai fini par faire ça avec le standard ed:

ed -s sometextfile <<< $'-2,$d\nwq'

Cela supprime les 2 dernières lignes à l' aide de montage en place (bien qu'il n'utilise un fichier temporaire dans !!)/tmp


5

Pour tronquer les fichiers très volumineux réellement en place, nous avons une truncatecommande. Il ne connaît pas les lignes, mais tail+ wcpeut convertir des lignes en octets:

file=bigone.log
lines=3
truncate -s -$(tail -$lines $file | wc -c) $file

Il existe une condition de concurrence évidente si le fichier est écrit en même temps. Dans ce cas, il peut être préférable d'utiliser head- il compte les octets à partir du début du fichier (disque mental IO), donc nous tronquerons toujours la limite de ligne (éventuellement plus de lignes que prévu si le fichier est écrit activement):

truncate -s $(head -n -$lines $file | wc -c) $file

Une seule ligne pratique si vous échouez à la tentative de connexion en mettant le mot de passe à la place du nom d'utilisateur:

truncate -s $(head -n -5 /var/log/secure | wc -c) /var/log/secure

4

Cela pourrait fonctionner pour vous (GNU sed):

sed ':a;$!N;1,4ba;P;$d;D' file

Agréable. Vous avez manqué l'apostrophe de fin ( ').
Thor

désolé pour un commentaire si tardif mais j'essaie et (adapté pour mon AIX / posix) il n'a pas pu imprimer tout sauf la dernière ligne. En lisant le code, je ne comprends pas comment les quatre dernières lignes sont supprimées, la boucle explicite est sur 4 premières lignes donc elle boucle certainement après und , Dou Pavec GNU sed et pas sur la version posix. Il semble que les lignes ne soient pas imprimées après Det restent dans la mémoire tampon de travail pour une nouvelle boucle sans passer à la «fin» de la ligne d'actions.
NeronLeVelu

@NeronLeVelu le programme lit dans une fenêtre de 4 lignes dans l'espace du motif, puis ajoute la ligne suivante et imprime la première jusqu'à ce qu'il atteigne la fin du fichier où il supprime les lignes restantes.
potong

@potong oui, je teste sur un sed GNU et il garde le tampon entre les lignes où posix le décharge après avoir Dfait l'effet inverse.
NeronLeVelu

4

La plupart des réponses ci-dessus semblent nécessiter des commandes / extensions GNU:

    $ head -n -2 myfile.txt
    -2: Badly formed number

Pour une solution légèrement plus portable:

     perl -ne 'push(@fifo,$_);print shift(@fifo) if @fifo > 10;'

OU

     perl -ne 'push(@buf,$_);END{print @buf[0 ... $#buf-10]}'

OU

     awk '{buf[NR-1]=$0;}END{ for ( i=0; i < (NR-10); i++){ print buf[i];} }'

Où "10" est "n".


2

Avec les réponses ici, vous auriez déjà appris que sed n'est pas le meilleur outil pour cette application.

Cependant, je pense qu'il existe un moyen de le faire en utilisant sed; L'idée est d'ajouter N lignes pour contenir de l'espace jusqu'à ce que vous puissiez lire sans toucher EOF. Lorsque EOF est atteint, imprimez le contenu de l'espace d'attente et quittez.

sed -e '$!{N;N;N;N;N;N;H;}' -e x

La commande sed ci-dessus omettra les 5 dernières lignes.


2

Essayez la commande suivante:

n = line number
tail -r file_name | sed '1,nd' | tail -r

Veuillez expliquer comment cela fonctionne. FYI - pour initialiser les variables shell, nous ne devrions pas avoir d'espace autour =.
codeforester

@codeforester La première ligne était un commentaire, je suppose. Il utilise juste tail -rlà où les autres ont utilisé tacpour inverser l'ordre des lignes et faire des dernières nlignes les npremières lignes.
Nicolas Melay

2

Cela peut se faire en 3 étapes:

a) Comptez le nombre de lignes du fichier que vous souhaitez éditer:

 n=`cat myfile |wc -l`

b) Soustrayez de ce nombre le nombre de lignes à supprimer:

 x=$((n-3))

c) Dites à sed de supprimer de ce numéro de ligne ( $x) jusqu'à la fin:

 sed "$x,\$d" myfile

Mauvais maths. Si vous devez supprimer 3 lignes, soustrayez 3 mais AJOUTEZ 1. Avec vos calculs, si le fichier a 10 lignes, 10 - 3 = 7 et que vous utilisez sedpour supprimer les lignes 7 à 10, soit 4 lignes, pas 3.
mathguy

1

Vous pouvez obtenir le nombre total de lignes avec wc -l <file>et utiliser

head -n <total lines - lines to remove> <file>


1

Cela supprimera les 3 dernières lignes de file:

for i in $(seq 1 3); do sed -i '$d' file; done;


1
C'est bien trop cher pour les gros fichiers - le fichier entier doit être lu et réécrit n fois! Et autant de fourches pour sed.
codeforester

bien que ce ne soit peut-être pas la solution la plus efficace, c'est de loin la plus simple et la plus facile à comprendre
Dharam

0

Je préfère cette solution;

head -$(gcalctool -s $(cat file | wc -l)-N) file

N est le nombre de lignes à supprimer.


0
sed -n ':pre
1,4 {N;b pre
    }
:cycle
$!{P;N;D;b cycle
  }' YourFile

version posix


0

Pour supprimer les 4 dernières lignes:

$ nl -b a file | sort -k1,1nr | sed '1, 4 d' | sort -k1,1n | sed 's/^ *[0-9]*\t//'   

un peu lourd (surtout en ressources) comparé à une tête. Au moins tac file | sed '1,4d' | tacparce que trier puis supprimer le préfixe coûte beaucoup de ressources.
NeronLeVelu

@NeronLeVelu vous avez raison mais il n'y a pas de taccommande dans certains systèmes (par exemple FreeBSD?)
mstafreshi

0

Je suis venu avec ceci, où n est le nombre de lignes que vous souhaitez supprimer:

count=`wc -l file`
lines=`expr "$count" - n`
head -n "$lines" file > temp.txt
mv temp.txt file
rm -f temp.txt

C'est un petit rond-point, mais je pense que c'est facile à suivre.

  1. Comptez le nombre de lignes dans le fichier principal
  2. Soustrayez le nombre de lignes que vous souhaitez supprimer du compte
  3. Imprimez le nombre de lignes que vous souhaitez conserver et stocker dans un fichier temporaire
  4. Remplacez le fichier principal par le fichier temporaire
  5. Supprimer le fichier temporaire

0

Pour supprimer les N dernières lignes d'un fichier, vous pouvez utiliser le même concept de

$ sed '2,4d' file

Vous pouvez utiliser un combo avec la commande tail pour inverser le fichier: si N vaut 5

$ tail -r file | sed '1,5d' file | tail -r > file

Et cette manière fonctionne également là où la head -n -5 filecommande ne s'exécute pas (comme sur un mac!).


-2

Cela supprimera les 12 dernières lignes

sed -n -e :a -e '1,10!{P;N;D;};N;ba'

1
Un peu d'explication aiderait s'il vous plaît.
Richard Wiseman
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.