31

Under a UNIX shell, how can I get a similar effect to the watch command, but with paging so that I can scroll around in the output if it takes up more than one screen?

In other words, I want a program that is to watch what less is to cat.

As an example, lets say I wanted to watch the output of qstat, I could use

watch qstat

to watch the output of qstat, but this can only shows the first screenful.

With a paging version of watch, I would be able to move around in the output as it is still continuously updated by watch. Is there any way to do this at the moment with existing utilities?

13 Answers13

21

Rather than modifying the 'watch' command, use screen!

For example, let's say that you need to be able to see 300 lines of height and 100 characters of width and move around that. After starting screen, force the size thus:

C-a :height -w 300
C-a :width -w 100

Now start your watch command. You can then use C-a <ESC> to page around the display.

Unfortunately, the display doesn't refresh while in copy mode. But if you want to adjust which section of the window you're viewing, the easiest way may be to rerun the height/width commands as by default your terminal shows the lower-right of the virtual window.

henry
  • 103
MikeyB
  • 40,079
8

You can try this:

$ while vmstat; do sleep 1; done | less

replace vmstat with qstat and adjust the sleep to your needs.

slm
  • 8,010
4

Multitail: http://www.vanheusden.com/multitail/

Example:

 vmstat 1 |multitail -j

Scroll back by press 'b' and page/arrow up/down.

2

OK, I've had a little go at a watchless function. It's a bit rough, and it doesn't yet appear to completely work, but here goes:

#!/bin/bash -u
out=$(mktemp)
(while [ 1 ]; do
    "$@" > $out;
    sleep 2;
done) &
less $out
kill $!

You have to manually use the R key in less to get the display to update.

It appears to work for watchless date but not for watchless qstat or watchless pstree, which both show blank. Any ideas?

1

I implement a simple python script to satisfy this request, named "watchall"

get it by: pip install watchall

replace watch with watchall and enjoy scrollable screen. now it only supports -n and -d flags.

0

I am using this:

while cat /etc/wgetrc; do sleep 10; done | pv -q -L 150 | tail -n +0 -f
0

I edited the script here to work with command line

#!/bin/bash
#
# watch a file and scroll
#
# keys => arrow-up/down, page-up/down, pos1, end
#
# usages:
#           swatch -n <timeout_watch> <file>
#           swatch <file>
#
# version:          1.1
# dependencies:     awk , tput , clear, read
# published:        https://unix.stackexchange.com/questions/3842/how-can-i-scroll-within-the-output-of-my-watch-command
# gif recording:    peek , https://github.com/phw/peek

=============================================

KEYCODES

=============================================

https://unix.stackexchange.com/questions/294908/read-special-keys-in-bash

showkey -a

=============================================

DEFAULTS

=============================================

command="" TMPFILE=$(mktemp) line_show_begin=1 line_show_begin_last=-1 console_lines_correction=4 timeout_watch=5 timeout_read=.1

=============================================

DEFINE Escape-Sequences

=============================================

http://ascii-table.com/ansi-escape-sequences-vt-100.php

ESC_clr_line='\033[K' ESC_reset_screen='\033c' ESC_clr_screen='\033[2J' ESC_cursor_pos='\033[0;0f' ESC_cursor_home='\033[H'

=============================================

FUNCTIONS

=============================================

function fn_help() { cat << EOF Usage: ./$0 [-n <timeout>] [<command>] , timeout >0.1s , default 5s EOF }

function get_options() { [[ "$1" == "" ]] && { fn_help ; exit 1 ; } while [ -n "$1" ]; do case "$1" in -h|--help) fn_help ;; -n) [[ "$2" == "" ]] && { echo "Error: option -n required <timeout>" ; exit 1 ; } if [[ "$(echo "$2<0.1"|bc)" == "0" ]] ; then timeout_watch="$2" shift else echo "Error: timeout <0.1 not allowed" exit 1 fi ;; -) echo "Error: unknown option »$1«" exit 1 ;; ) #if [[ -f "$1" ]] ; then command=$1 #else # echo "Error: file not found »$1«" # exit 1 #fi ;; esac shift done [[ "$command" == "" ]] && { echo "Error: command required" ; exit 1 ; } }

function 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" }

function fn_print_file() { # --------------------------------------------------- # file lenght can change while watch # --------------------------------------------------- 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 postion changed
# ---------------------------------------------------

if (( &quot;$line_show_begin&quot; != &quot;$line_show_begin_last&quot; )) ; then
    line_show_begin_last=$line_show_begin;
    clear
else
    printf $ESC_cursor_home
fi

# ---------------------------------------------------
# print file section
# ---------------------------------------------------

fn_print_headline
eval $command &gt; $TMPFILE
awk -v var1=&quot;$line_show_begin&quot; -v var2=&quot;$console_lines&quot; 'NR&gt;=var1 {if (NR&gt;var1+var2) {exit 0} else {printf &quot;%s\n&quot;,$0 } }' $TMPFILE

}

function fn_console_size_change() { console_columns=$(tput cols) console_lines=$(($(tput lines)-$console_lines_correction)) line_show_begin_last=-1 }

function fn_quit() { echo "quit" $0 , $? setterm -cursor on ; exit 0 }

=============================================

GET OPTIONS

=============================================

get_options "$@" # pass all arguments with double-quotes

=============================================

INIT TRAP

=============================================

trap "fn_console_size_change" SIGWINCH # https://en.wikipedia.org/wiki/Signal_(IPC)#SIGWINCH trap "fn_quit" INT TERM EXIT

=============================================

MAIN

=============================================

fn_console_size_change setterm -cursor off

while true ; do fn_print_file read -rsn1 -t $timeout_watch k # char 1 case "$k" in [[:graph:]]) # Normal input handling ;; $'\x09') # TAB # Routine for selecting current item ;; $'\x7f') # Back-Space # Routine for back-space ;; $'\x01') # Ctrl+A # 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) # Arrow-Up-Key (( "$line_show_begin" > "1" )) && line_show_begin=$(($line_show_begin-1)) ;; B) # Arrow-Down-Key (( "$line_show_begin" < "$line_last" )) && line_show_begin=$(($line_show_begin+1)) ;; H) # Pos1-Key line_show_begin=1 ;; F) # End-Key line_show_begin=$line_last ;; 5) # PgUp-Key read -rsn1 -t $timeout_read k # char 4

                if [[ &quot;$k&quot; == &quot;~&quot; ]] &amp;&amp; (( &quot;$line_show_begin&quot; &gt; &quot;$(($console_lines/2))&quot; )) ; 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 [[ &quot;$k&quot; == &quot;~&quot; ]] &amp;&amp; (( &quot;$line_show_begin&quot; &lt; &quot;$(($line_last-$console_lines/2))&quot; )) ; 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

  • create a file in ~/bin/cwatch.sh
nano ~/bin/cwatch.sh
  • change files properties to make it runnable:
chmod +x ~/bin/cwatch.sh
  • edit ~/.bashrc and add alias
alias cwatch="~/bin/cwatch.sh"

now you can try it:

cwatch 'ps aux | grep -v grep'
0

In case this could be useful to others, this is how I solved the issue on my side. In the "cmd" function, plug any command you want to monitor.

#!/bin/bash

function cmd { sudo lsof -i -n -P | grep 11.12.13.14:8883 }

echo "" >previous.log while true; do cmd >out.log
diff out.log previous.log >/dev/null cc="$?" if [[ "$cc" != "0" ]]; then date=date --rfc-3339=seconds epoch=date +%s echo "" echo "Changes on $date ($epoch)" cat out.log cp out.log previous.log fi sleep 0.5 done

0

I don't see how this could be implemented as the row contents change, and watch would reset back to first line every 2 seconds even if you could scroll down.

Some workarounds are:

watch 'qstat | tail -n40' to show output of qstat beginning from 40th line from bottom

watch 'qstat | grep jsmith' to grep the output so the lines you are interested in are always in the first screen.

Note that you need to put the commands around the pipe in single quotes - otherwise you will be piping the output of watch, not the output of qstat.

enkrs
  • 121
0

To continue on enkrs's answer,

watch 'qstat | head -300 | tail -15'

will get you arbitrary pages into the qstat's output.

0

Here's a rather crude script that seems to work for several commands that I threw at it

#!/bin/bash
# ---- mywatch.sh ----

if [ $# -lt 1 && $# -gt 2 ]; then
    echo "Usage: $0 <command> <delay>" 
    exit 1
fi

CMD=$1
if [ $# -eq 2 ]; then
  DELAY=$2
else
  DELAY=2 # default
fi

while : ; do
  ( (echo -e "Every ${DELAY}s: $CMD\n"; $CMD) | less )&
  PID=$!
  sleep $DELAY
  kill -9 $PID &> /dev/null
  clear
done

Used as such:

alias mywatch="~/bin/mywatch.sh"

mywatch vmstat
mywatch "ps aux" # commands in options need to be quoted
mywaych pstree 10 # change delays

Being rather pedantic, the transition between refreshes aren't as smooth as I would like it to be. Naturally, being a simple script it doesn't support highlight of diff (watch -d). Also, the parsing of input arguments can be done better.

Shawn Chin
  • 1,904
0

How about just: tail -f

geeklin
  • 538
-1

you can try:

watch command > file

then in your file you should see the appendend output (I don't have a linux box rigth now to test this)