Если ваши сегменты не очень большие (как, например: вы действительно не можете сэкономить столько ОЗУ, предположительно потому, что это крошечная встроенная система, управляющая большой файловой системой), один подход - действительно лучший подход. Не только потому, что это будет быстрее, но и самое главное, потому что это позволяет источнику быть потоком, из которого любые данные, считанные и не сохраненные, будут потеряны. Это действительно работа для awk, хотя sed тоже может это сделать.
sed -n -e 's/^---$//' -e 't a' \
-e 'H' -e '$g' -e '$s/^\n//' -e '$p' -e 'b' \
-e ':a' -e 'h' # you are not expected to understand this
awk '{if (/^---$/) {chunk=""} # separator ==> start new chunk
else {chunk=chunk $0 RS}} # append line to chunk
END {printf "%s", chunk}' # print last chunk (without adding a newline)
Если вы должны использовать двухпроходный подход, определите смещение строки последнего разделителя и напечатайте из него. Или определите смещение байта и распечатайте с него.
</input/file tail -n +$((1 + $(</input/file # print the last N lines, where N=…
grep -n -e '---' | # list separator line numbers
tail -n 1 | # take the last one
cut -d ':' -f 1) )) # retain only line number
</input/file tail -n +$(</input/file awk '/^---$/ {n=NR+1} END {print n}')
</input/file tail -c +$(</input/file LC_CTYPE=C awk '
{pos+=length($0 RS)} # pos contains the current byte offset in the file
/^---$/ {last=pos} # last contains the byte offset after the last separator
END {print last+1} # print characters from last (+1 because tail counts from 1)
')
Приложение: Если у вас больше POSIX, вот простая однопроходная версия, основанная на общем расширении awk, которое позволяет разделителю записей RS
быть регулярным выражением (POSIX допускает только один символ). Это не совсем правильно: если файл заканчивается разделителем записей, он печатает фрагмент перед разделителем последней записи вместо пустой записи. Вторая версия использует RT
этот недостаток, но RT
она специфична для GNU awk.
awk -vRS='(^|\n)---+($|\n)' 'END{printf $0}'
gawk -vRS='(^|\n)---+($|\n)' 'END{if (RT == "") printf $0}'
Жиль "ТАК - перестань быть злым"
источник
sed
работает нормально, но я не могуawk
запустить пример; он зависает ... и я получаю ошибку в 3-м примере:cut -f ':' -t 1
... cut: неверный параметр - 't'cut
примере. Я не вижу ничего плохого в этомawk
примере, какую версию awk вы используете и каков ваш тестовый ввод?awk
версия работает .. это просто занимает очень много времени на большом файле ..sed
версия обработала тот же файл за 0.470 с .. Мои тестовые данные очень взвешены ... только два куска с одиноким '---' три строки с конца миллиона строк ...Стратегия с двумя проходами кажется правильной. Вместо sed я бы использовал
awk(1)
. Два прохода могут выглядеть так:чтобы получить номер строки. И затем отобразите весь текст, начиная с этого номера строки:
Это не должно требовать чрезмерной буферизации.
источник
awk -v line=$(awk '/^---$/{n=NR}END{print n}' file) 'NR>line' file
Первый
sed
выводит номера строк строк "---" ...Второй
sed
извлекает последний номер из выходных данных первого sed ...Добавьте 1 к этому числу, чтобы получить начало вашего блока "ccc" ...
Третий 'sed' выводит из начала блока "ccc" в EOF
Обновление (с исправленной информацией о методах Жиля)
Что ж, меня интересовало, как будут работать Гленн Джекман
tac
, поэтому я проверил время на три ответа (на момент написания) ... Каждый тестовый файл (-ы) содержал 1 миллион строк (их собственных номеров строк).Все ответы сделали то, что ожидалось ...
Вот времена ..
Жиль
sed
(один проход)Жиль
awk
(один проход)Жиль «два прохода» (первый метод)
Жиль "два прохода" (второй метод) ... очень быстро
Жиль «два прохода» (третий метод)
Жиль "gawk" (метод RT) ... очень быстрый , но не POSIX.
Гленн Джекман ... очень быстро , но не POSIX.
fred.bear
Маки Мессер
источник
Используйте « tac », который выводит строки файла от конца к началу:
источник
tac
это не POSIX, это специфично для Linux (в GNU coreutils и в некоторых установках busybox).Вы могли бы просто использовать
ed
Как это работает:
t
дублирует.
строку current ( ) - которая всегда является последней строкой, когдаed
начинается (только в случае, если в последней строке присутствует разделитель),1,?===?d
удаляет все строки до и включая предыдущее совпадение (ed
все еще находится на последней строке ) затем$d
удаляет (дублирует) последнюю строку,,p
печатает текстовый буфер (замените на,w
чтобы отредактировать файл на месте) и, наконец,q
завершает работуed
.Если вы знаете, что на входе есть хотя бы один разделитель (и вам все равно, напечатан ли он), тогда
будет короче.
Как это работает: он добавляет все строки в
H
старый буфер, перезаписываетh
старый буфер при обнаружении совпадения, онd
выбирает все строки, кроме$
последней, когда онx
изменяет буферы (и автопечать).источник