The tail command has a quite glaring omission in that it can't truncate lines.
Thus it wraps long log line into multiple terminal lines regardless. Which makes them very hard to read.
I used to work around this using less -S
and then hitting the [F] key but that's interactive. less +F <filename>
is the little known work-around for the interactive issue but that still doesn't work well with pipes (tail -f logfile | grep "ERROR:"
etc).
There is a bug report from 2004 against GNU coreutils but that went nowhere.
So we're not getting a tail -S
anytime soon.
Bash to the rescue: tail -S → tails
Hence I wrote this little script, tails [1kB]:
#!/bin/bash -i
# v2 from 170712: introduce loop to work around GNU coreutils issues with pipe/fifo/isatty
if [[ -z "$COLUMNS" ]] ; then
MYCOL=$(tput cols)
else
MYCOL=${COLUMNS}
fi
tail "$@" | while read line; do
echo "$line" | expand | cut -c1-${MYCOL:-80}
done
Now, there are some interesting bits even in this tiny script:
The bash -i
results in $COLUMNS
being set within the script on sane Linux bash. Otherwise that variable wouldn't be available. Because it is a shell variable and not an environment variable. You knew that, right?
Unfortunately the bash -i
doesn't get $COLUMNS
set on either MacOS (X) or FreeBSD, so that's where the tput cols
comes into play. It outputs the column width for the current terminal to stdout.
If all that fails tails will default to 80 columns.
So tails -f /var/log/apache/access.log
will now look nice.
Corner case: color
If you use color codes somewhere (grep --color=always
, dmesg --color=always
) tails will just truncate lines too short so they will still not wrap.
There is a slight risk that it may cut into half a color code escape sequence and mess up the terminal a bit.
You could change that by removing the -i
from the shebang line and setting $COLUMNS explicitly. But that then needs manual adjustment for each combination of colored lines (=count of ANSI sequences) and terminal width. Better to color after the tails invocation then where possible, e.g. tails -f /var/log/httpd/error.log | grep ':error'
to watch for PHP errors and the like.
Mended corner cases: inconsistent tail behaviour
A first version of the script didn't use a loop but just had
tail "$@" | expand | cut -c1-${MYCOL:-80}
This would break tails -f
on Debian (coreutils 8.23) / Ubuntu (coreutils 8.26) while removing the |expand
would make it work. On Fedora 25 (coreutils 8.25) I couldn't get tails -f
to work at all with that v1. The cut
(so just a single command chained) already broke the pipe . And nope, stdbuf
didn't help.
If you have a more simple solution to work around the isatty / isfifo mess, please leave a comment!
Alternatives
If you want to show multiple log tails in parallel, highlight strings etc. multitail is worth a look.
Depending on what you want to achieve you could also tell your terminal emulator to not wrap lines:
setterm -linewrap off; less -SR +F /var/log/apache/access.log; setterm -linewrap on