Some of my scripts on a game server send a console command and then read the answer from the server log. The answer is a block of lines between a start line and an end line, and the log keeps every earlier block too. The scripts needed only the newest block, without the marker lines.
A couple of tac pipelines didn’t work, so I went back to awk. It does this in one pass. Collect each block, keep the last one, print it at the end:
awk -v start='START MARKER' -v end='END MARKER' '
$0 ~ start { block = ""; inside = 1; next }
$0 ~ end { if (inside) last = block; inside = 0; next }
inside { block = block $0 "\n" }
END { printf "%s", last }
' server.log
Reset block on every start line. My first working version didn’t, and it only looked right because my test log had a single block in it.
Pass the patterns with -v. Pasting shell variables into the awk program inside the quotes works until a pattern contains a quote or a slash.
The invisible \r
Next, a script pulled a number out of that block and did math with it:
invalid arithmetic operator (error token is "
The error token looks empty. It’s a carriage return at the end of the captured value. Whatever produced that output used \r\n line endings. Strip it before you use the value:
count=$(sed -n 's/^Players: //p' last_block.txt | tr -d '\r')
echo $(( count + 1 ))