watch: add -r to not rexec on terminal resize

If you have the watched program doing some other thing every time its
run and you resize the window, you might get unexpected results. The
-r option lets you run only when the interval has expired.

References:
 procps-ng/procps!125
 procps-ng/procps#190
This commit is contained in:
Craig Small 2023-01-17 20:45:48 +11:00
parent 5f4074a250
commit b2bfd76b06
3 changed files with 56 additions and 35 deletions

1
NEWS
View File

@ -9,6 +9,7 @@ procps-ng-NEXT
* vmstat: Referesh memory statistics Debian #1027963 * vmstat: Referesh memory statistics Debian #1027963
* w: Add --pids option merge #159 * w: Add --pids option merge #159
* watch: Pass through beep issue #104 * watch: Pass through beep issue #104
* watch: -r option to not re-exec on SIGWINCH merge #125
procps-ng-4.0.2 procps-ng-4.0.2
--------------- ---------------

View File

@ -1,4 +1,4 @@
.TH WATCH 1 "2023-01-16" "procps-ng" "User Commands" .TH WATCH 1 "2023-01-17" "procps-ng" "User Commands"
.SH NAME .SH NAME
watch \- execute a program periodically, showing output fullscreen watch \- execute a program periodically, showing output fullscreen
.SH SYNOPSIS .SH SYNOPSIS
@ -13,12 +13,26 @@ allows you to watch the program output change over time. By default,
\fIcommand\fR is run every 2 seconds and \fBwatch\fR will run until interrupted. \fIcommand\fR is run every 2 seconds and \fBwatch\fR will run until interrupted.
.SH OPTIONS .SH OPTIONS
.TP .TP
\fB\-b\fR, \fB\-\-beep\fR
Beep if command has a non-zero exit.
.TP
\fB\-c\fR, \fB\-\-color\fR
Interpret ANSI color and style sequences.
.TP
\fB\-d\fR, \fB\-\-differences\fR[=\fIpermanent\fR] \fB\-d\fR, \fB\-\-differences\fR[=\fIpermanent\fR]
Highlight the differences between successive updates. If the optional Highlight the differences between successive updates. If the optional
\fIpermanent\fR argument is specified then \fIpermanent\fR argument is specified then
.B watch .B watch
will show all changes since the first iteration. will show all changes since the first iteration.
.TP .TP
\fB\-e\fR, \fB\-\-errexit\fR
Freeze updates on command error, and exit after a key press.
.TP
\fB\-g\fR, \fB\-\-chgexit\fR
Exit when the output of
.I command
changes.
.TP
\fB\-n\fR, \fB\-\-interval\fR \fIseconds\fR \fB\-n\fR, \fB\-\-interval\fR \fIseconds\fR
Specify update interval. The command will not allow quicker than 0.1 second Specify update interval. The command will not allow quicker than 0.1 second
interval, in which the smaller values are converted. Both '.' and ',' work interval, in which the smaller values are converted. Both '.' and ',' work
@ -38,28 +52,21 @@ Try it with
(if present) and notice how the fractional seconds stays (nearly) the same, as opposed to (if present) and notice how the fractional seconds stays (nearly) the same, as opposed to
normal mode where they continuously increase. normal mode where they continuously increase.
.TP .TP
\fB\-t\fR, \fB\-\-no\-title\fR
Turn off the header showing the interval, command, and current time at the
top of the display, as well as the following blank line.
.TP
\fB\-b\fR, \fB\-\-beep\fR
Beep if command has a non-zero exit.
.TP
\fB\-e\fR, \fB\-\-errexit\fR
Freeze updates on command error, and exit after a key press.
.TP
\fB\-g\fR, \fB\-\-chgexit\fR
Exit when the output of
.I command
changes.
.TP
\fB\-q\fR, \fB\-\-equexit\fR <cycles> \fB\-q\fR, \fB\-\-equexit\fR <cycles>
Exit when output of Exit when output of
.I command .I command
does not change for the given number of cycles. does not change for the given number of cycles.
.TP .TP
\fB\-c\fR, \fB\-\-color\fR \fB\-r\fR, \fB\-\-no-rerun\fR
Interpret ANSI color and style sequences. Do not run the program on terminal resize, the output of the program will re-appear at the next
regular run time.
.TP
\fB\-t\fR, \fB\-\-no\-title\fR
Turn off the header showing the interval, command, and current time at the
top of the display, as well as the following blank line.
.TP
\fB\-w\fR, \fB\-\-no\-wrap\fR
Turn off line wrapping. Long lines will be truncated instead of wrapped to the next line.
.TP .TP
\fB\-x\fR, \fB\-\-exec\fR \fB\-x\fR, \fB\-\-exec\fR
Pass Pass
@ -70,9 +77,6 @@ instead of
.B sh \-c .B sh \-c
which reduces the need to use extra quoting to get the desired effect. which reduces the need to use extra quoting to get the desired effect.
.TP .TP
\fB\-w\fR, \fB\-\-no\-wrap\fR
Turn off line wrapping. Long lines will be truncated instead of wrapped to the next line.
.TP
\fB\-h\fR, \fB\-\-help\fR \fB\-h\fR, \fB\-\-help\fR
Display help text and exit. Display help text and exit.
.TP .TP
@ -134,7 +138,9 @@ itself.
Upon terminal resize, the screen will not be correctly repainted until the Upon terminal resize, the screen will not be correctly repainted until the
next scheduled update. All next scheduled update. All
.B \-\-differences .B \-\-differences
highlighting is lost on that update as well. highlighting is lost on that update as well. When using the
.B \-\-no\-rerun
option, no output of will be visible.
Non-printing characters are stripped from program output. Use \fBcat -v\fR as Non-printing characters are stripped from program output. Use \fBcat -v\fR as
part of the command pipeline if you want to see them. part of the command pipeline if you want to see them.

View File

@ -72,6 +72,7 @@ static int flags;
#define WATCH_ERREXIT (1 << 6) #define WATCH_ERREXIT (1 << 6)
#define WATCH_CHGEXIT (1 << 7) #define WATCH_CHGEXIT (1 << 7)
#define WATCH_EQUEXIT (1 << 8) #define WATCH_EQUEXIT (1 << 8)
#define WATCH_NORERUN (1 << 9)
static int curses_started = 0; static int curses_started = 0;
static long height = 24, width = 80; static long height = 24, width = 80;
@ -101,6 +102,7 @@ static void __attribute__ ((__noreturn__))
" exit when output from command does not change\n"), out); " exit when output from command does not change\n"), out);
fputs(_(" -n, --interval <secs> seconds to wait between updates\n"), out); fputs(_(" -n, --interval <secs> seconds to wait between updates\n"), out);
fputs(_(" -p, --precise attempt run command in precise intervals\n"), out); fputs(_(" -p, --precise attempt run command in precise intervals\n"), out);
fputs(_(" -r, --no-rerun do not rerun program on window resize\n"), out);
fputs(_(" -t, --no-title turn off header\n"), out); fputs(_(" -t, --no-title turn off header\n"), out);
fputs(_(" -w, --no-wrap turn off line wrapping\n"), out); fputs(_(" -w, --no-wrap turn off line wrapping\n"), out);
fputs(_(" -x, --exec pass command to exec instead of \"sh -c\"\n"), out); fputs(_(" -x, --exec pass command to exec instead of \"sh -c\"\n"), out);
@ -814,6 +816,7 @@ int main(int argc, char *argv[])
char *command; char *command;
char **command_argv; char **command_argv;
int command_length = 0; /* not including final \0 */ int command_length = 0; /* not including final \0 */
watch_usec_t last_run = 0;
watch_usec_t next_loop; /* next loop time in us, used for precise time watch_usec_t next_loop; /* next loop time in us, used for precise time
* keeping only */ * keeping only */
#ifdef WITH_WATCH8BIT #ifdef WITH_WATCH8BIT
@ -832,6 +835,7 @@ int main(int argc, char *argv[])
{"equexit", required_argument, 0, 'q'}, {"equexit", required_argument, 0, 'q'},
{"exec", no_argument, 0, 'x'}, {"exec", no_argument, 0, 'x'},
{"precise", no_argument, 0, 'p'}, {"precise", no_argument, 0, 'p'},
{"no-rerun", no_argument, 0, 'r'},
{"no-title", no_argument, 0, 't'}, {"no-title", no_argument, 0, 't'},
{"no-wrap", no_argument, 0, 'w'}, {"no-wrap", no_argument, 0, 'w'},
{"version", no_argument, 0, 'v'}, {"version", no_argument, 0, 'v'},
@ -851,7 +855,7 @@ int main(int argc, char *argv[])
interval = strtod_nol_or_err(interval_string, _("Could not parse interval from WATCH_INTERVAL")); interval = strtod_nol_or_err(interval_string, _("Could not parse interval from WATCH_INTERVAL"));
while ((optc = while ((optc =
getopt_long(argc, argv, "+bced::ghq:n:pvtwx", longopts, (int *)0)) getopt_long(argc, argv, "+bced::ghq:n:prtwvx", longopts, (int *)0))
!= EOF) { != EOF) {
switch (optc) { switch (optc) {
case 'b': case 'b':
@ -875,6 +879,9 @@ int main(int argc, char *argv[])
flags |= WATCH_EQUEXIT; flags |= WATCH_EQUEXIT;
max_cycles = strtod_nol_or_err(optarg, _("failed to parse argument")); max_cycles = strtod_nol_or_err(optarg, _("failed to parse argument"));
break; break;
case 'r':
flags |= WATCH_NORERUN;
break;
case 't': case 't':
show_title = 0; show_title = 0;
break; break;
@ -990,18 +997,25 @@ int main(int argc, char *argv[])
output_header(command, interval); output_header(command, interval);
#endif /* WITH_WATCH8BIT */ #endif /* WITH_WATCH8BIT */
int exit = run_command(command, command_argv); if (!(flags & WATCH_NORERUN) ||
if (flags & WATCH_EQUEXIT) { get_time_usec() - last_run > interval * USECS_PER_SEC) {
if (cycle_count == max_cycles && exit) { last_run = get_time_usec();
break; int exit = run_command(command, command_argv);
} else if (exit) {
cycle_count++; if (flags & WATCH_EQUEXIT) {
} else { if (cycle_count == max_cycles && exit) {
cycle_count = 0; break;
} } else if (exit) {
} else if (exit) { cycle_count++;
break; } else {
} cycle_count = 0;
}
} else if (exit) {
break;
}
} else {
refresh();
}
if (precise_timekeeping) { if (precise_timekeeping) {
watch_usec_t cur_time = get_time_usec(); watch_usec_t cur_time = get_time_usec();