"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.
精彩评论