Last active
March 10, 2025 12:52
-
-
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`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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