web-dev-qa-db-fra.com

Supprimer la dernière ligne d'un fichier dans Bash

J'ai un fichier, foo.txt, contenant les lignes suivantes:

a
b
c

Je veux une commande simple qui aboutisse au contenu de foo.txt:

a
b
291
Fragsworth

Utilisation de GNU sed :

_sed -i '$ d' foo.txt
_

L'option _-i_ n'existe pas dans les versions _GNU sed_ antérieures à 3.95. Vous devez donc l'utiliser comme filtre avec un fichier temporaire:

_cp foo.txt foo.txt.tmp
sed '$ d' foo.txt.tmp > foo.txt
rm -f foo.txt.tmp
_

Bien sûr, dans ce cas, vous pouvez également utiliser _head -n -1_ au lieu de sed.

MacOS:

Sur Mac OS X (à partir de 10.7.4), l’équivalent de la commande _sed -i_ ci-dessus est

_sed -i '' -e '$ d' foo.txt
_
358
thkala

C'est de loin la solution la plus simple et la plus rapide, en particulier pour les gros fichiers:

head -n -1 foo.txt > temp.txt ; mv temp.txt foo.txt

si vous souhaitez supprimer la ligne supérieure, utilisez ceci:

tail -n +2 foo.txt

ce qui signifie que les lignes de sortie commencent à la ligne 2.

N'utilisez pas sed pour supprimer les lignes situées en haut ou en bas d'un fichier - il est très lent si le fichier est volumineux.

258
John

J'ai eu du mal avec toutes les réponses ici parce que je travaillais avec un fichier ÉNORME (~ 300 Go) et aucune des solutions n'a été mise à l'échelle. Voici ma solution:

dd if=/dev/null of=<filename> bs=1 seek=$(echo $(stat --format=%s <filename> ) - $( tail -n1 <filename> | wc -c) | bc )

En mots: Déterminez la longueur du fichier que vous souhaitez utiliser (longueur du fichier moins la longueur de la dernière ligne, en utilisant bc) et définissez cette position comme étant la fin du fichier (en dding un octet de /dev/null dessus).

C’est rapide parce que tail commence à lire à partir de la fin, et dd écrasera le fichier à la place plutôt que de copier (et d’analyser) chaque ligne du fichier, ce qui les autres solutions font.

NOTE: Ceci supprime la ligne du fichier en place! Faites une sauvegarde ou un test sur un fichier factice avant de l'essayer sur votre propre fichier!

108
Yossi Farjoun

Pour supprimer la dernière ligne d'un fichier sans lire le fichier en entier ni réécrire quoi que ce soit , vous pouvez utiliser

tail -n 1 "$file" | wc -c | xargs -I {} truncate "$file" -s -{}

Pour supprimer la dernière ligne et également l’imprimer sur la sortie standard ("la" la faire "), vous pouvez combiner cette commande avec tee:

tail -n 1 "$file" | tee >(wc -c | xargs -I {} truncate "$file" -s -{})

Ces commandes peuvent traiter efficacement un très gros fichier. Cela ressemble à la réponse de Yossi et s’inspire de celle-ci, mais évite d’utiliser quelques fonctions supplémentaires.

Si vous envisagez de les utiliser de manière répétée et souhaitez gérer les erreurs et certaines autres fonctionnalités, vous pouvez utiliser la commande poptail ici: https://github.com/donm/evenmoreutils

52
ohspite

Utilisateurs Mac

si vous voulez seulement que la dernière ligne soit supprimée sans changer le fichier lui-même,

sed -e '$ d' foo.txt

si vous voulez supprimer la dernière ligne du fichier d’entrée lui-même,

sed -i '' -e '$ d' foo.txt

28
manpreet singh

Pour les utilisateurs de Mac:

Sur Mac, head -n-1 ne fonctionnera pas. Et j’essayais de trouver une solution simple [sans me soucier du temps de traitement] pour résoudre ce problème en utilisant seulement des commandes "tête" et/ou "queue".

J'ai essayé la séquence de commandes suivante et j'étais heureux de pouvoir la résoudre en utilisant simplement la commande "tail" [avec les options disponibles sur Mac]. Donc, si vous êtes sur Mac et que vous voulez utiliser uniquement "tail" pour résoudre ce problème, vous pouvez utiliser cette commande:

cat fichier.txt | queue -r | queue -n +2 | queue -r

Explication:

1> tail -r: inverse simplement l'ordre des lignes dans son entrée

2> tail -n +2: ceci affiche toutes les lignes à partir de la deuxième ligne dans son entrée

24
Sarfraaz Ahmed
echo -e '$d\nw\nq'| ed foo.txt
13
lhf
awk 'NR>1{print buf}{buf = $0}'

Ce code dit essentiellement ce qui suit:

Pour chaque ligne après la première, imprimez la ligne mise en mémoire tampon

pour chaque ligne, réinitialiser le tampon

La mémoire tampon est décalée d’une ligne, d’où l’impression des lignes 1 à n-1.

8
Foo Bah
awk "NR != `wc -l < text.file`" text.file |> text.file

Cet extrait fait l'affaire.

0
Michael Kingski

Voici comment vous pouvez le faire manuellement (personnellement, j'utilise beaucoup cette méthode lorsque je dois supprimer rapidement la dernière ligne d'un fichier):

vim + [FILE]

Ce signe + signifie que lorsque le fichier est ouvert dans l’éditeur de texte vim, le curseur se positionne sur la dernière ligne du fichier.

Maintenant, appuyez deux fois sur d sur votre clavier. Cela fera exactement ce que vous voulez - supprimez la dernière ligne. Ensuite, appuyez sur : suivi de x, puis appuyez sur Enter. Cela enregistrera les modifications et vous ramènera à l'environnement de ligne de commande. Maintenant, la dernière ligne a été supprimée avec succès.

0
Michael Rybkin

Ces deux solutions sont ici sous d'autres formes. J'ai trouvé cela un peu plus pratique, clair et utile:

En utilisant dd:

BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
dd if=${ORIGINALFILE} of=${ORIGINALFILE}.tmp status=none bs=1 count=$(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc )
/bin/mv -f ${ORIGINALFILE}.tmp ${ORIGINALFILE}

Utilisation de tronquer:

BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
truncate -s $(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc ) ${ORIGINALFILE}
0
virtual-light