Skip to content

Instantly share code, notes, and snippets.

@ELLIOTTCABLE
Last active March 10, 2025 12:52
Show Gist options
  • Save ELLIOTTCABLE/1c5afda811c1c4b822cf75361e8ded2f to your computer and use it in GitHub Desktop.
Save ELLIOTTCABLE/1c5afda811c1c4b822cf75361e8ded2f to your computer and use it in GitHub Desktop.
Use `less +F` on multiple files merged into a single stream, just like `tail -f`
# lessf: `less +F` for multiple files, ala `tail -f`
#
# Usage:
# lessf file1.log file2.log ...
#
# - should work on dash, bash, and zsh;
# - works on macOS and the Linuxes I've tested it on;
# - requires the minimal tools that seem to be available nearly everywhere (`awk`, `mktemp`), and of course `less`
# - you may want `unbuffer` or `stdbuf` to avoid the 4kb of buffering (i.e. no output until enough loglines have been added.)
#
# See also, if you can install Actual Software, and want a ncurses-based tool or more features:
# <https://www.vanheusden.com/multitail/>
lessf() (
if ! command -v unbuffer >&/dev/null; then
if unb_bin="$(command -v stdbuf)"; then
unbuffer() { "$unb_bin" -o0 "$@" ;}
else
printf "WARN: You probably want \`unbuffer\` from the 'expect' package or \`stdbuf\` from 'coreutils'.\n" >&2
printf "WARN: Without them, output is buffered, and loglines may not appear immediately!\n" >&2
sleep 5
fi
fi
pad="7"
for arg in "$@"; do
fname="${arg##*/}"
fname="${fname%.log}"
if [ ${#fname} -gt "${pad}" ]; then
pad="${#fname}"
fi
done
tmpfile="$(mktemp "$TMPDIR/lessf.XXXXXX")"
# shellcheck disable=SC2064
trap "rm -f '$tmpfile'; trap - EXIT" EXIT INT HUP QUIT TERM
printf "Following" >"$tmpfile"
printf " '%s'," "$@" >>"$tmpfile"
unbuffer tail -n10 -f "$@" \
| awk "$(cat <<AWK
# Drop blank lines
/^$/ {next};
# If the line starts with '==>', split the path and store the components in 'cmp'
/^==> / {
n = split(substr(\$0, 5, length - 8), cmp, "/")
sub(/\.log\$/, "", cmp[n])
next
}
# Print the last component of the path prepended to the logline
{
printf "%${pad}s: %s\n", cmp[n], \$0
}
AWK
)" >>"$tmpfile" &
less -SRX +F "$tmpfile"
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment