Удалить последнюю строку из файла в 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
) и установите эту позицию в конец файла (по dd
ing один байт /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: это печатает все строки, начиная со второй строки на входе
awk 'NR>1{print buf}{buf = }'
по сути, этот код говорит следующее:
для каждой строки после первой выведите буферизованную строку
для каждой строки, сбросить буфер
буфер отстает на одну строку, поэтому вы в конечном итоге печатаете строки от 1 до n-1
оба этих решения находятся здесь в других формах. Я нашел их немного более практичными, ясными и полезными:--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}