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

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

a
b
c

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

a
b

Ответ 1

Использование GNU sed:

sed -i '$ d' foo.txt

Опция -i не существует в версиях 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.

MacOS:

В Mac OS X (по состоянию на 10.7.4) эквивалентом команды sed -i выше является

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

Ответ 2

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

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

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

tail -n +2 foo.txt

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

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

Ответ 3

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

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

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

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

ПРИМЕЧАНИЕ. Это удаляет строку из файла на месте! Сделайте резервную копию или проверку на фиктивный файл перед тем, как попробовать его в своем собственном файле!

Ответ 4

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

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 -{})

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

Если вы собираетесь использовать их повторно и хотите обработать ошибки и некоторые другие функции, вы можете использовать команду poptail здесь: https://github.com/donm/evenmoreutils

Ответ 5

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

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

sed -e '$ d' foo.txt

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

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

Ответ 6

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

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

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

cat file.txt | tail -r | хвост -n +2 | tail -r

Объяснение:

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

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

Ответ 7

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

Ответ 8

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

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

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

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

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

Ответ 9

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

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

Ответ 10

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

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

Использование truncate:

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

Ответ 11

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

vim + [FILE]

Этот знак + означает, что при открытии файла в текстовом редакторе vim курсор будет расположен на последней строке файла.

Теперь просто дважды нажмите d на клавиатуре. Это будет делать именно то, что вы хотите - удалить последнюю строку. После этого нажмите :, затем x, а затем нажмите Enter. Это сохранит изменения и вернет вас в оболочку. Теперь последняя строка была успешно удалена.

Ответ 12

Linux

$ - последняя строка, d для удаления:

sed '$d' ~/path/to/your/file/name

MacOS

Эквивалент седа -i

sed -i '' -e '$ d' ~/path/to/your/file/name

Ответ 13

Рубин (1.9 +)

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