Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env bash
- # watch a file or command output and scroll within
- #
- # keys => arrow-up/down, page-up/down, pos1, end
- #
- # usages:
- # swatch.sh -n <timeout_watch> <file|command>
- # swatch.sh <file|command>
- #
- # version: 1.2 (macOS compatible)
- # dependencies: awk, tput, clear, read
- # published: https://unix.stackexchange.com/questions/3842/how-can-i-scroll-within-the-output-of-my-watch-command
- # =============================================
- # DEFAULTS
- # =============================================
- TMPFILE=$(mktemp)
- line_show_begin="1"
- line_show_begin_last="-1"
- console_lines_correction="4"
- timeout_watch="2"
- timeout_read=".1"
- # http://ascii-table.com/ansi-escape-sequences-vt-100.php
- ESC_cursor_home='\033[H'
- define(){ IFS=$'\n' read -r -d '' "${1}" || true; }
- define helptext <<-EOF
- Usage: ${0##*/} [-n <timeout>] '[<command>]'
- timout : in seconds or fractions of seconds [default: ${timeout_watch}s]
- command: any command wished to be observed - best applied in quotes
- EOF
- __init() {
- trap "fn_console_size_change" SIGWINCH
- trap "fn_quit" INT HUP TERM QUIT EXIT
- fn_console_size_change
- tput civis
- }
- fn_help() {
- printf "%s\n" "${helptext}"
- }
- get_options() {
- [[ "$1" == "" ]] && fn_help 1
- while [ -n "$1" ]; do
- case "$1" in
- -h|--help)
- fn_help 0
- ;;
- -n)
- [[ "$2" == "" ]] && { echo "Error: option -n required <timeout>" ; exit 1 ; }
- timeout_watch="$2" && shift
- ;;
- -*) echo "Error: unknown option »$1«"; exit 1; ;;
- *) command=$1;;
- esac
- shift
- done
- [[ "$command" == "" ]] && { echo "Error: command required" ; exit 1 ; }
- }
- fn_print_headline() {
- hdl_txt_right="${HOSTNAME}: $(date "+%Y-%m-%d %H:%M:%S")"
- hdl_txt_left="$command, [${timeout_watch}s, $line_show_begin]"
- hdl_txt_left_length=${#hdl_txt_left}
- printf '%s%*s\n\n' "$hdl_txt_left" "$((console_columns - hdl_txt_left_length))" "$hdl_txt_right"
- }
- fn_print_file() {
- # file length can change during watch execution
- eval "$command" > "$TMPFILE"
- lines_command=$(awk 'END {print NR}' "$TMPFILE")
- line_last=$((lines_command-console_lines))
- (( "$line_last" < "1" )) && { line_last=1; clear; }
- (( "$line_show_begin" > "$line_last" )) && { line_show_begin=$line_last; clear; }
- # print position changed
- if (( "$line_show_begin" != "$line_show_begin_last" )); then
- line_show_begin_last=$line_show_begin
- clear
- else
- printf "$ESC_cursor_home"
- fi
- # print file section
- fn_print_headline
- eval "$command" > "$TMPFILE"
- awk -v var1="$line_show_begin" -v var2="$console_lines" 'NR>=var1 {if (NR>var1+var2) {exit 0} else {printf "%s\n",$0 } }' "$TMPFILE"
- }
- fn_console_size_change() {
- console_columns=$(tput cols)
- console_lines=$(($(tput lines) - console_lines_correction))
- line_show_begin_last=-1
- }
- fn_quit() {
- tput cnorm
- tput clear
- exit 0
- }
- # =============================================
- # MAIN
- # =============================================
- get_options "$@"
- __init
- while :; do
- fn_print_file
- read -rsn1 -t "$timeout_watch" k # char 1
- case "$k" in
- [[:graph:]]) # Normal input handling
- ;;
- $'\x09') # Routine for selecting current item
- ;;
- $'\x7f') # Routine for back-space
- ;;
- $'\x01') # Routine for ctrl+a
- ;;
- $'\x1b') # ESC
- read -rsn1 k # char 2
- [[ "$k" == "" ]] && return # Esc-Key
- [[ "$k" == "[" ]] && read -rsn1 -t $timeout_read k # char 3
- [[ "$k" == "O" ]] && read -rsn1 -t $timeout_read k # char 3
- case "$k" in
- A) (( "$line_show_begin" > "1" )) && ((line_show_begin--)) ;; # Arrow-Up-Key
- B) (( "$line_show_begin" < "$line_last" )) && ((line_show_begin++)) ;; # Arrow-Down-Key
- H) line_show_begin=1 ;; # Pos1-Key
- F) line_show_begin=$line_last ;; # End-Key
- 5) # PgUp-Key
- read -rsn1 -t $timeout_read k # char 4
- if [[ "$k" == "~" ]] && (( "$line_show_begin" > "$((console_lines/2))" )) ; then
- line_show_begin=$((line_show_begin-console_lines/2))
- else
- line_show_begin=1
- fi
- ;;
- 6) # PgDown-Key
- read -rsn1 -t $timeout_read k # char 4
- if [[ "$k" == "~" ]] && (( "$line_show_begin" < "$((line_last-console_lines/2))" )) ; then
- line_show_begin=$((line_show_begin+console_lines/2))
- else
- line_show_begin=$line_last
- fi
- ;;
- esac
- read -rsn4 -t $timeout_read # Try to flush out other sequences ...
- ;;
- esac
- done
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement