#!/bin/bash usage() { local self="${0##*/}" local err=$1; shift echo >&2 "usage: $self DIR [DIR...]" echo >&2 "" echo >&2 "$err" exit 3 } warn() { echo >&2 "$@" } die() { echo >&2 "$@" exit 3 } list_files() { local dir for dir in "${Dirs[@]}"; do echo "$dir/root.log" seq -f "$dir/task-rep%02.0f.log" 0 3 seq -f "$dir/task-cmd%02.0f.log" 0 9 done } open_files() { local i=0 local path=0 for path in "$@"; do twinner -t "$path" -O "$Tmp/pid-$i" -P -c "tail -F \"$path\"" & sleep 0.1 # allow WM to have predictable order of windows ((i++)) done } onclose() { warn "" warn "got SIGINT; killing: Pids=(${Pids[*]})" kill "${Pids[@]}" rm -r "$Tmp" } main() { test "$#" -eq 0 && usage "no DIRs?" local Dirs=("$@") local filelist=() local Pids=() local Tmp Tmp=$(mktemp -d /tmp/watch_logs.XXXXXXXX) list_files >"$Tmp/files" mapfile -t filelist <"$Tmp/files" open_files "${filelist[@]}" sleep 2 cat "$Tmp/pid-"* > "$Tmp/pids" mapfile -t Pids <"$Tmp/pids" warn "spawned children: ${Pids[*]}" warn "press ^C to close all open files" wait # "${Pids[@]}" rm -r "$Tmp" } trap onclose SIGINT main "$@"