views:

220

answers:

2

I had this question... answered and very nice it was too. But, oddity has emerged whereby if the log file has a unique last line, (i.e. the first few words are different to the preceeding lines) it correctly returns that last line with tail -n 1 "file" but if the last few lines are similar to the the last line, it returns all the lines that are similar.

Let me show you....

The file it's reading is...

frame= 1065 fps= 30 q=1.6 size=   11977kB time=35.54 bitrate=2761.1kbits/s    
frame= 1081 fps= 30 q=2.7 size=   12174kB time=36.07 bitrate=2765.0kbits/s    
frame= 1097 fps= 30 q=2.7 size=   12332kB time=36.60 bitrate=2759.9kbits/s    
frame= 1113 fps= 30 q=3.0 size=   12487kB time=37.14 bitrate=2754.4kbits/s    
frame= 1129 fps= 30 q=2.4 size=   12652kB time=37.67 bitrate=2751.3kbits/s    
frame= 1145 fps= 30 q=2.4 size=   12824kB time=38.20 bitrate=2749.7kbits/s    
frame= 1161 fps= 30 q=2.4 size=   12996kB time=38.74 bitrate=2748.1kbits/s    
frame= 1176 fps= 30 q=2.7 size=   13162kB time=39.24 bitrate=2747.8kbits/s    
frame= 1191 fps= 30 q=2.6 size=   13328kB time=39.74 bitrate=2747.4kbits/s    
frame= 1206 fps= 30 q=2.5 size=   13496kB time=40.24 bitrate=2747.5kbits/s    
frame= 1222 fps= 30 q=2.5 size=   13685kB time=40.77 bitrate=2749.6kbits/s    
frame= 1240 fps= 30 q=4.2 size=   13954kB time=41.38 bitrate=2762.8kbits/s    
frame= 1261 fps= 31 q=4.6 Lsize=   14428kB time=42.08 bitrate=2809.1kbits/s    
video:13889kB audio:494kB global headers:0kB muxing overhead 0.314239%

$line = `tail -n 1 "$logfile"`;

RETURNS...

video:13889kB audio:494kB global headers:0kB muxing overhead 0.314239%

However, if that last, more unique line, isn't there... it returns:-

frame= 1065 fps= 30 q=1.6 size=   11977kB time=35.54 bitrate=2761.1kbits/s    
frame= 1081 fps= 30 q=2.7 size=   12174kB time=36.07 bitrate=2765.0kbits/s    
frame= 1097 fps= 30 q=2.7 size=   12332kB time=36.60 bitrate=2759.9kbits/s    
frame= 1113 fps= 30 q=3.0 size=   12487kB time=37.14 bitrate=2754.4kbits/s    
frame= 1129 fps= 30 q=2.4 size=   12652kB time=37.67 bitrate=2751.3kbits/s    
frame= 1145 fps= 30 q=2.4 size=   12824kB time=38.20 bitrate=2749.7kbits/s    
frame= 1161 fps= 30 q=2.4 size=   12996kB time=38.74 bitrate=2748.1kbits/s    
frame= 1176 fps= 30 q=2.7 size=   13162kB time=39.24 bitrate=2747.8kbits/s    
frame= 1191 fps= 30 q=2.6 size=   13328kB time=39.74 bitrate=2747.4kbits/s    
frame= 1206 fps= 30 q=2.5 size=   13496kB time=40.24 bitrate=2747.5kbits/s    
frame= 1222 fps= 30 q=2.5 size=   13685kB time=40.77 bitrate=2749.6kbits/s    
frame= 1240 fps= 30 q=4.2 size=   13954kB time=41.38 bitrate=2762.8kbits/s    
frame= 1261 fps= 31 q=4.6 Lsize=   14428kB time=42.08 bitrate=2809.1kbits/s
+5  A: 

Those lines are seperated by "\r", i.e. a carriage return, not a line feed, because ffmpeg (that's what you're using, right?) wants to show them on the same line of the console. Tail, however, expects "\n" as a line seperator.

To summarize our little comment chat below: Calling

$line = `sed -e "s/\\r/\\n/g" $file | tail -n 1`

will replace the carriage returns by line feeds before calling tail, thus giving the expected results.

balpha
Excellent point. For explanation reasons... On old line based systems, \r was used to reset the horizontal position while \n was used to move one line down vertically. Hence, \r\n moved the cursor to the start of the next line. Most *NIX systems have moved to simply \n since those days, but \r still has it's meaning.
Matthew Scharley
Right, bang on. Is there a way to adjust what tail looks for, or another command?
WiseDonkey
You could put sed -e "s/\r/\n/" into the pipeline.
balpha
Err, of course that should have been: ie. $line = `sed -e "s/\r/\n/" $file | tail -n 1`
Matthew Scharley
I was just about to ask for that i.e. :)But... $line = `sed -e "s/\r/\n/" $logfile | tail -n 1`;Which I guess you meant (extra ") doesn't return any result.
WiseDonkey
Error log shows sed: -e expression #1, char 4: unterminated `s' command
WiseDonkey
Replace \r by \\r and \n by \\n to escape the backslash.
balpha
Hmm. Done as you suggest balpha and the problem is now back to square one. Anymore thoughts?
WiseDonkey
Ok, works with muteW's close to your suggestion line. Thanks a lot for your responses. can't seem to give two ticks :)
WiseDonkey
The missing "g" is the problem; muteW had it right. s///g means to replace all (and not just one) occurences per line. And since sed expects \n as the line terminator as well, that's necessary.
balpha
+1: got the sed idea from you, just had to fine tune it and workout the global(/g) and escaping(\\) issues.
muteW
+3  A: 

Could you maybe open the file with a hex-editor and check which character is used as a separator between the "frame" lines. I think there might be something other than a newline character between the frame lines which is why 'tail' returns the entire block instead of just the last line (which in this case happens to be the entire frame block).

Substitute the carriage return with a newline as so

$line = `sed 's|\\r|\\n|g' "$logfile"| tail -n 1`;

Make sure you include the global switch ('g') at the end of the regex passed to sed as shown above.

muteW
Hi muteW, thanks for the edit. Same problem as above. Error log shows sed: -e expression #1, char 4: unterminated `s' command.How do I terminate that then?
WiseDonkey
Add an extra '\' before \r and \n to escape the characters.
muteW
Now works, thank you muteW.
WiseDonkey
+1 You had it right faster.
balpha
ah, good point about the g modifier. The whole problem was that it was one line, so of course. Oh well.
Matthew Scharley