У меня есть файл foo.txt
, содержащий следующие строки:
a
b
c
Мне нужна простая команда, которая приводит к тому, что содержимое foo.txt
будет:
a
b
У меня есть файл foo.txt
, содержащий следующие строки:
a
b
c
Мне нужна простая команда, которая приводит к тому, что содержимое foo.txt
будет:
a
b
Использование 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
Это, безусловно, самое быстрое и простое решение, особенно в больших файлах:
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 )
В словах: найдите длину файла, в который вы хотите закончить (длина файла минус длина его последней строки, используя bc
), и установите эту позицию как конец файла ( на dd
на один байт /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 -{})
Эти команды могут эффективно обрабатывать очень большой файл. Это похоже на ответ Йоси и вдохновляется им, но он избегает использования нескольких дополнительных функций.
Если вы собираетесь использовать их повторно и хотите обработать ошибки и некоторые другие функции, вы можете использовать команду poptail
здесь:
https://github.com/donm/evenmoreutils
Пользователи Mac
если вы хотите, чтобы последняя строка удаляла вывод без изменения самого файла do
sed -e '$ d' foo.txt
если вы хотите удалить последнюю строку самого входного файла do
sed -i '' -e '$ d' foo.txt
На 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: это печатает все строки, начиная со второй строки на входе
echo -e '$d\nw\nq'| ed foo.txt
awk 'NR>1{print buf}{buf = $0}'
По существу, этот код говорит следующее:
Для каждой строки после первой печати буферизованная строка
для каждой строки, reset буфер
Буфер отстает на одну строку, поэтому вы заканчиваете печать строк 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}
Использование truncate:
BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
truncate -s $(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc ) ${ORIGINALFILE}
Вот как вы можете сделать это вручную (я лично часто использую этот метод, когда мне нужно быстро удалить последнюю строку в файле):
vim + [FILE]
Этот знак +
означает, что при открытии файла в текстовом редакторе vim курсор будет расположен на последней строке файла.
Теперь просто дважды нажмите d
на клавиатуре. Это будет делать именно то, что вы хотите - удалить последнюю строку. После этого нажмите :
, затем x
, а затем нажмите Enter
. Это сохранит изменения и вернет вас в оболочку. Теперь последняя строка была успешно удалена.
sed '$d' ~/path/to/your/file/name
sed -i '' -e '$ d' ~/path/to/your/file/name
Рубин (1.9 +)
ruby -ne 'BEGIN{prv=""};print prv ; prv=$_;' file