Usuń ostatnią linię z pliku w Bash

Mam plik foo.txt, zawierający następujące wiersze:

a
b
c

Chcę prostej komendy, która spowoduje, że zawartość foo.txt będzie:

a
b
Author: Mateusz Piotrowski, 2011-02-03

11 answers

Za pomocą GNU sed:

sed -i '$ d' foo.txt

Opcja -i nie istnieje w wersji GNU sed starszej niż 3.95, więc musisz użyć jej jako filtra z plikiem tymczasowym:

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

Oczywiście, w takim przypadku można również użyć head -n -1 zamiast sed.

 293
Author: thkala,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-23 21:43:29

Jest to zdecydowanie najszybsze i najprostsze rozwiązanie, szczególnie na dużych plikach:

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

Jeśli chcesz usunąć górną linię użyj tego:

tail -n +2 foo.txt

Co oznacza linie wyjściowe zaczynające się od linii 2.

Nie używaj sed do usuwania linii z górnej lub dolnej części pliku - jest to bardzo wolne, jeśli plik jest duży.

 217
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-22 15:17:29

Miałem problem ze wszystkimi odpowiedziami tutaj, ponieważ pracowałem z ogromnym plikiem (~300GB) i Żadne z rozwiązań się nie skalowało. Oto moje rozwiązanie:

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

W słowach: Znajdź długość pliku, z którym chcesz skończyć (długość pliku minus długość jego ostatniej linii, używając bc) i ustaw tę pozycję jako koniec pliku (przez dd w jednym bajcie /dev/null).

Jest to szybkie, ponieważ tail zaczyna czytać od końca, a dd nadpisze plik zamiast kopiować (i analizować) każdą linię pliku, co robią inne rozwiązania.

Uwaga: spowoduje to usunięcie linii z pliku w miejscu! Zrób kopię zapasową lub przetestuj na fałszywym pliku przed wypróbowaniem go na własnym pliku!

 95
Author: Yossi Farjoun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-06 19:34:09

Aby usunąć ostatnią linię z pliku bez czytania całego pliku lub przepisywania czegokolwiek , możesz użyć

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

Aby usunąć ostatnią linię I wydrukować ją na stdout ("pop"), możesz połączyć to polecenie z tee:

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

Te polecenia mogą efektywnie przetwarzać bardzo duży plik. Jest to podobne i inspirowane odpowiedzią Yossi, ale unika korzystania z kilku dodatkowych funkcji.

Jeśli masz zamiar używać ich wielokrotnie i chcesz obsługi błędów i niektóre inne funkcje, możesz użyć polecenia poptail tutaj: https://github.com/donm/evenmoreutils

 44
Author: ohspite,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-27 13:53:49

Użytkownicy Komputerów Mac

Jeśli chcesz usunąć tylko ostatnią linię bez zmiany samego pliku wykonaj

sed -e '$ d' foo.txt

Jeśli chcesz usunąć ostatnią linię samego pliku wejściowego wykonaj

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

 24
Author: manpreet singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-05 06:26:05

Dla Użytkowników Komputerów Mac:

Na Macu, head-n -1 nie będzie działać. I starałem się znaleźć proste rozwiązanie [ bez martwienia się o czas przetwarzania], aby rozwiązać ten problem tylko za pomocą poleceń" head "i / lub" tail".

Próbowałem następującej sekwencji poleceń i byłem szczęśliwy, że mogłem rozwiązać go za pomocą polecenia "tail" [z opcjami dostępnymi na Macu]. Tak więc, jeśli jesteś na komputerze Mac i chcesz użyć tylko "tail", aby rozwiązać ten problem, możesz użyć tego polecenia:

Kot plik.txt / tail-r | tail-n +2 | tail-R

Wyjaśnienie:

1> tail - r: po prostu odwraca kolejność linii na wejściu

2> tail-n +2: wyświetla wszystkie linie zaczynające się od drugiej linii na wejściu

 15
Author: Sarfraaz Ahmed,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-16 03:37:51
echo -e '$d\nw\nq'| ed foo.txt
 12
Author: lhf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-28 06:03:49
awk 'NR>1{print buf}{buf = $0}'

Zasadniczo ten kod mówi co następuje:

Dla każdej linii po pierwszej wyświetla buforowaną linię

Dla każdej linii zresetuj bufor

Bufor jest opóźniony o jedną linię, stąd kończy się Drukowanie linii od 1 do n-1

 8
Author: Foo Bah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-03 01:47:44
awk "NR != `wc -l < text.file`" text.file |> text.file

Ten fragment załatwia sprawę.

 0
Author: Michael Kingski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-13 15:09:53

Oba te rozwiązania są tutaj w innych formach. Okazało się, że są trochę bardziej praktyczne, przejrzyste i przydatne: {]}

Użycie 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}

Użycie truncate:

BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
truncate -s $(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc ) ${ORIGINALFILE}
 0
Author: virtual-light,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-16 16:27:06

Ruby (1.9+)

ruby -ne 'BEGIN{prv=""};print prv ; prv=$_;' file
 -3
Author: kurumi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-03 02:43:24