A menos que seus segmentos sejam realmente grandes (como em: você realmente não pode poupar muita RAM, presumivelmente porque este é um pequeno sistema embarcado que controla um grande sistema de arquivos), uma única passagem é realmente a melhor abordagem. Não apenas porque será mais rápido, mas o mais importante, porque permite que a fonte seja um fluxo, a partir do qual qualquer dado lido e não salvo é perdido. Este é realmente um trabalho para o awk, embora o sed também possa fazer isso.
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)
Se você precisar usar uma abordagem de dois passos, determine o deslocamento de linha do último separador e imprima a partir dele. Ou determine o deslocamento de bytes e imprima a partir disso.
</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)
')
Adendo: Se você tem mais que POSIX, aqui está uma versão simples de um passo que depende de uma extensão comum ao awk que permite que o separador de registro RS
seja uma expressão regular (POSIX só permite um único caractere). Não está completamente correto: se o arquivo terminar com um separador de registro, ele imprimirá o fragmento antes do último separador de registro em vez de um registro vazio. A segunda versão usando RT
evita esse defeito, mas RT
é específico do GNU awk.
awk -vRS='(^|\n)---+($|\n)' 'END{printf $0}'
gawk -vRS='(^|\n)---+($|\n)' 'END{if (RT == "") printf $0}'