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