开发者

"tail -f" alternate which doesn't scroll the terminal window

I want to check a file at continuous intervals for contents which keep changing. "tail -f" doesn't suffice as the file doesn't grow in size.

I could use a simple while loop in bash to the same effect:

while [ 1 ]; do cat /proc/acpi/battery/BAT1/state ; sleep 10; done

It works, although it has the unwanted effect of scro开发者_Python百科lling my terminal window.

So now I'm wondering, is there a linux/shell command that would display the output of this file without scrolling the terminal?


watch -n 10 cat /proc/acpi/battery/BAT1/state

You can add the -d flag if you want it to highlight the differences from one iteration to the next.


watch is your friend. It uses curses so it won't scroll your terminal.

Usage: watch [-dhntv] [--differences[=cumulative]] [--help] [--interval=<n>] [--no-title] [--version] <command>
  -d, --differences[=cumulative]        highlight changes between updates
                (cumulative means highlighting is cumulative)
  -h, --help                            print a summary of the options
  -n, --interval=<seconds>              seconds to wait between updates
  -v, --version                         print the version number
  -t, --no-title                        turns off showing the header

So taking your example it'll be:

watch -n 10 cat /proc/acpi/battery/BAT1/state


Combining several ideas from other answers plus a couple of other tricks, this will output the file without clearing the screen or scrolling (except for the first cycle if the prompt is at the bottom of the screen).

up=$(tput cuu1)$(tput el); while true; do (IFS=$'\n'; a=($(</proc/acpi/battery/BAT1/state)); echo "${a[*]}"; sleep 1; printf "%.0s$up" ${a[@]}); done

It's obviously something you wouldn't type by hand, so you can make it a function that takes the filename, the number of seconds between updates, starting line and number of lines as arguments.

watchit () {
    local up=$(tput cuu1)$(tput el) IFS=$'\n' lines
    local start=${3:-0} end
    while true
    do
        lines=($(<"$1"))
        end=${4:-${#lines[@]}}
        echo "${lines[*]:$start:$end}"
        sleep ${2:-1}
        # go up and clear each line
        printf "%.0s$up" "${lines[@]:$start:$end}"
    done
}

Run it:

watchit /proc/acpi/battery/BAT1/state .5 0 6

The second argument (seconds between updates) defaults to 1. The third argument (starting line) defaults to 0. The fourth argument (number of lines) defaults to the whole file. If you omit the number of lines and the file grows it may cause scrolling to accommodate the new lines.

Edit: I added an argument to control the frequency of updates.


My favorite, which works in places that don't have watch, is this:

while true; do clear ; cat /proc/acpi/battery/BAT1/state ; sleep 10; done


The canonical (and easiest, and most flexible) answer is watch, as others have said. But if you want to see just the first line of a file, here's an alternative that neither clears nor scrolls the terminal:

while line=`head -n 1 /proc/acpi/battery/BAT1/state` \
    && printf "%s\r" "$line" \
    && sleep 10
do
    printf "%s\r" "`echo -n "$line" | sed 's/./ /g'`"
done
echo

The carriage return is the core concept here. It tells the cursor to return to the beginning of the current line, like a newline but without moving to the next line. The printf command is used here because (1) it doesn't automatically add a newline, and (2) it translates \r into a carriage return.

The first printf prints your line. The second one clears it by overwriting it with spaces, so that you don't see garbage if the next line to be printed is shorter.

Note that if the line printed is longer than the width of your terminal, the terminal will scroll anyway.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜