Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tail the most recent file

Tags:

linux

bash

tail

I have a program that logs its output to an *.out file when running. I set up a bash script to run several different times, so each run writes to a different *.out file. I found that I could tail the most recent *.out file like this:

watch tail $(ls -tr *.out | tail -n1)

The problem seems to be that the referencing $() only gets executed once. So when the first run finishes, watch continues to tail the same *.out file, even though there is now a newer *.out file.

How can I alter this to go to the next *.out file after one run finishes?

I tried doing some nesting of quotes and parentheses, but I don't really understand the details of referencing. Matters are complicated by the fact that watch passes its command to sh, even though I'm using bash.

Bonus points: it would be great if this could be modified to tail -f instead of just repeating watch every n seconds.

like image 486
Jeff Irwin Avatar asked Oct 19 '22 17:10

Jeff Irwin


2 Answers

I also dealt with this problem and finally came to this solution:

 watch "ls -t1 | sed q | xargs tail"

Need to get a bit hacky for the bonus. The tail command also supports an argument --pid which makes tail die as soon as the referenced PID dies. Sounds good? Here's some pattern you could use:

while true; do ls -t1 | sed q | xargs lsof -F np | sed 's/.\(.*\)/\1/g' | xargs tail -f --pid 2>/dev/null ; done

This basically tracks the most current file and restarts tail when the file writing process ends.

like image 118
steffen Avatar answered Oct 21 '22 08:10

steffen


If all the files exist to begin with, and you have a modern implementation of tail that can handle multiple files,

tail -f *.out

would seem to be the best solution. But if you don't have all the files to begin with, then it would still be easiest if you just created them. *.out will expand only to the files you already have.

But if you can't know the filenames for tail -f before you start, then you will need to restart tail if any new outfiles are created while you are tailing. In that case, given you are only writing to each outfile one at a time, you could do:

inotifywait -m -e create -q . | while read dir event file; do
    kill %tail
    tail -f "$file" &
done
kill %tail

(The above requires inotifywait, which is included in inotify-tools on Debian-based systems like Ubuntu.) It watches the current directory for newly created files, tails whichever file was created, in the background, and kills the previous tail command whenever a new file is created.

like image 32
kojiro Avatar answered Oct 21 '22 07:10

kojiro