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


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

a
b
c

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

a
b
11 242

11 ответов:

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

sed -i '$ d' foo.txt

The не существует 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 для удаления линий от верхней или нижней части файла ... это очень очень медленно, если файл большой.

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

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

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

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

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

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

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

чтобы удалить последнюю строку, а также распечатать ее на stdout ("pop" it), вы можете объединить эту команду с 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 не будет работать. И я пытался найти простое решение [ не беспокоясь о времени обработки], чтобы решить эту проблему только с помощью команд "head" и/или "tail".

я попробовал следующую последовательность команд и был счастлив, что могу решить ее, просто используя команду "хвост" [с опциями, доступными на 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

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

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

С помощью 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