14

when tailing multiple files at once as shown below, is any there any way to show the file name at the start of each line?

tail -f one.log two.log

current output

==> one.log <==
contents of one.log here...
contents of one.log here...

==> two.log <==
contents of one.log here...
contents of two.log here..

Looking for something like

one.log: contents of one.log here...
one.log: contents of one.log here...
two.log: contents of two.log here...
two.log: contents of two.log here...
  • You can look at the -v (verbose) option for tail . This may not exactly match your ask, but is a start. – rahul Apr 13 '15 at 10:23
  • multitail can do this I think – Gilles 'SO- stop being evil' Apr 13 '15 at 11:16
7
tail  -f ...your-files | 
    awk '/^==> / {a=substr($0, 5, length-8); next}
                 {print a":"$0}'

\thanks{don_cristti}

  • @don_crissti, thank you! (1) a vs file -- no more wine to my glass! (2) good idea. I start to do something like this but I lasily said to my self "no one will make tail -f of files with spaces" :) -- I will use your excellent suggestions. – JJoao Apr 14 '15 at 7:17
  • can you explain length-8? why it is 8 here, I know only 8 works. – Shicheng Guo May 24 '17 at 23:52
  • 1
    tail -n 1 *.txt | awk '/^==>/ {a=substr($0, 5, length-8); next} {print a,$1}' | awk '$2>0 {if ($2 !~/chrY/) print $1}' | xargs -I {} qsub {} – Shicheng Guo May 25 '17 at 0:04
  • @ShichengGuo, 8 = length("==> ")+length(" <==") – JJoao May 25 '17 at 7:27
  • 1
    surprisingly/amazingly your joojoo magic awk solution works! – Trevor Boyd Smith Sep 13 '19 at 15:28
6

Short answer

GNU Parallel has a set of nice options which make it really easy to do such things:

parallel --tagstring "{}:" --line-buffer tail -f {} ::: one.log two.log

The output would be:

one.log:	contents of one.log here...
one.log:	contents of one.log here...
two.log:	contents of two.log here...
two.log:	contents of two.log here...

More explanation

  • The option --tagstring=str tags each output line with string str. From parallel man page:
--tagstring str
                Tag lines with a string. Each output line will be prepended with
                str and TAB (\t). str can contain replacement strings such as {}.

                --tagstring is ignored when using -u, --onall, and --nonall.
  • All occurrences of {} will be replace by parallel's arguments which, in this case, are log file names; i.e. one.log and two.log (all arguments after :::).

  • The option --line-buffer is required because the output of a command (e.g. tail -f one.log or tail -f two.log) would be printed if that command is finished. Since tail -f will wait for file growth, it is required to print the output on line basis which --line-buffer does so. Again from parallel man page:

--line-buffer (alpha testing)
                Buffer output on line basis. --group will keep the output
                together for a whole job. --ungroup allows output to mixup with
                half a line coming from one job and half a line coming from
                another job. --line-buffer fits between these two: GNU parallel
                will print a full line, but will allow for mixing lines of
                different jobs.
2

If tail is not mandatory, you can use grep to achieve this:

grep "" *.log

This will print the filename as the prefix of each output line.

Output breaks if *.log expands to only one file. In this regard:

grep '' /dev/null *.log
  • I need to show file name in output of tail -f not grep. – mtk Apr 13 '15 at 10:15
  • @serenesat this would just print the entire contents of the files wouldn't it? The OP was asking for the filename to be printed when tail is specified – rahul Apr 13 '15 at 10:18
  • you can also just do --with-filename or -H to always force filename prepend. – Trevor Boyd Smith Sep 13 '19 at 15:21
  • i really love this answer! does exactly EXACTLY what is needed with a solution that is like 13 characters long. as opposed to tricky awk solution or parallel which isn't installed. – Trevor Boyd Smith Sep 13 '19 at 15:22
  • only problem is that if your logfiles are 1 million lines long. then your grep will spam 1 million lines to console (or over ssh)... – Trevor Boyd Smith Sep 13 '19 at 15:24
0

My idea would be to create a single file with merged logs from several files, like someone suggested here and prepend filenames:

$ tail -f /var/log/syslog | sed -u -E 's,(^.+$),/var/log/syslog: \1,g' >> /tmp/LOG &&
$ tail -f /var/log/Xorg.0.log | sed -u -E 's,(^.+$),/var/log/Xorg.0.log: \1,g' >> /tmp/LOG &&
$ tail -f /tmp/LOG
0

Something with xargs and sed could work:

$ xargs -I% -P0 sh -c "tail -f % | sed s/^/%:/g" <<EOT
one.log
two.log
EOT

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.