Удалить последнюю строку из файла в bash

у меня есть файл, foo.txt, содержащий следующие строки:

a
b
c

Я хочу простую команду, которая приводит к содержимому foo.txt время:

a
b

11 ответов


используя GNU sed:

sed -i '$ d' foo.txt

на не существует GNU sed версии 3.95, так что вы должны использовать его в качестве фильтра с временным файл:

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

конечно, в этом случае вы также можете использовать head -n -1 вместо sed.


Это, безусловно, самое быстрое и простое решение, особенно для больших файлов:

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

Если вы хотите удалить верхнюю строку, используйте это:

tail -n +2 foo.txt

что означает выходные линии, начинающиеся с линии 2.

не используйте sed для удаления строк из верхней или нижней части файла-это очень медленно, если файл большой.


у меня были проблемы со всеми ответами здесь, потому что я работал с огромным файлом (~300Gb), и ни одно из решений не масштабировалось. Вот мое решение:

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

in words: узнайте длину файла, который вы хотите получить (длина файла минус длина его последней строки, используя bc) и установите эту позицию в конец файла (по dding один байт /dev/null на него).

это быстро, потому что tail начинает читать с конца, и dd перезапишется файлом на месте вместо того, чтобы копировать (и анализировать) каждую строку файла, что делают другие решения.

Примечание: это удаляет строку из файла на месте! Сделайте резервную копию или тест на фиктивный файл, прежде чем попробовать его на свой собственный файл!


удалить последнюю строку из файла без чтения всего файла или переписывания чего-либо, вы можете использовать

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

чтобы удалить последнюю строку, а также распечатать ее на stdout ("pop"), вы можете объединить эту команду с tee:

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

эти команды могут эффективно обрабатывать очень большие файлы. Это похоже на ответ Йоси и вдохновлено им, но позволяет избежать использования нескольких дополнительных функций.

если вы собираетесь использовать эти повторно и хотите обработку ошибок и некоторые другие функции, вы можете использовать


Пользователи Mac

Если вы хотите удалить только последнюю строку без изменения самого файла, сделайте

sed -e '$ d' foo.txt

Если вы хотите удалить последнюю строку сам входной файл делаем

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


Для Пользователей Mac :

на Mac, head-n -1 не будет работать. И я пытался найти простое решение [ не беспокоясь о времени обработки], чтобы решить эту проблему только с помощью команд" голова "и/или" хвост".

я попробовал следующую последовательность команд и был рад, что могу решить ее, просто используя команду "хвост" [с параметрами, доступными на Mac ]. Итак, если вы находитесь на Mac и хотите использовать только "хвост" для решения этой проблемы, вы можете использовать эту команду :

файл cat.txt / tail-r / tail-n +2 / tail-r

объяснение :

1 > tail-r: просто меняет порядок строк на своем входе

2 > tail-n +2: это печатает все строки, начиная со второй строки на входе


echo -e '$d\nw\nq'| ed foo.txt

awk 'NR>1{print buf}{buf = }'

по сути, этот код говорит следующее:

для каждой строки после первой выведите буферизованную строку

для каждой строки, сбросить буфер

буфер отстает на одну строку, поэтому вы в конечном итоге печатаете строки от 1 до n-1


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

этот фрагмент делает трюк.


оба этих решения находятся здесь в других формах. Я нашел их немного более практичными, ясными и полезными:--3-->

использование 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}

С помощью усечения:

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

Рубин(1.9+)

ruby -ne 'BEGIN{prv=""};print prv ; prv=$_;' file