watch: Add --equexit option
This commit adds a new option called `--equexit` which is the opposite of `--chgexit`. This option makes it possible to exit when the output of the given command does not change for the given number of cycles. A download operation could be given as a use-case since `watch` will exit when the output does not change anymore, in other words, when the download is completed. References: procps-ng/procps#232 Signed-off-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
This commit is contained in:
parent
3f48e8bdfc
commit
3ac20bf536
5
watch.1
5
watch.1
@ -53,6 +53,11 @@ Exit when the output of
|
|||||||
.I command
|
.I command
|
||||||
changes.
|
changes.
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-equexit\fR <cycles>
|
||||||
|
Exit when output of
|
||||||
|
.I command
|
||||||
|
does not change for the given number of cycles.
|
||||||
|
.TP
|
||||||
\fB\-c\fR, \fB\-\-color\fR
|
\fB\-c\fR, \fB\-\-color\fR
|
||||||
Interpret ANSI color and style sequences.
|
Interpret ANSI color and style sequences.
|
||||||
.TP
|
.TP
|
||||||
|
46
watch.c
46
watch.c
@ -71,6 +71,7 @@ static int flags;
|
|||||||
#define WATCH_COLOR (1 << 5)
|
#define WATCH_COLOR (1 << 5)
|
||||||
#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)
|
||||||
|
|
||||||
static int curses_started = 0;
|
static int curses_started = 0;
|
||||||
static long height = 24, width = 80;
|
static long height = 24, width = 80;
|
||||||
@ -96,6 +97,8 @@ static void __attribute__ ((__noreturn__))
|
|||||||
" highlight changes between updates\n"), out);
|
" highlight changes between updates\n"), out);
|
||||||
fputs(_(" -e, --errexit exit if command has a non-zero exit\n"), out);
|
fputs(_(" -e, --errexit exit if command has a non-zero exit\n"), out);
|
||||||
fputs(_(" -g, --chgexit exit when output from command changes\n"), out);
|
fputs(_(" -g, --chgexit exit when output from command changes\n"), out);
|
||||||
|
fputs(_(" -q, --equexit <cycles>\n"
|
||||||
|
" 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(_(" -t, --no-title turn off header\n"), out);
|
fputs(_(" -t, --no-title turn off header\n"), out);
|
||||||
@ -561,6 +564,8 @@ static int run_command(char *restrict command, char **restrict command_argv)
|
|||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
pid_t child;
|
pid_t child;
|
||||||
int exit_early = 0;
|
int exit_early = 0;
|
||||||
|
int buffer_size = 0;
|
||||||
|
int unchanged_buffer = 0;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
/* allocate pipes */
|
/* allocate pipes */
|
||||||
@ -703,6 +708,20 @@ static int run_command(char *restrict command, char **restrict command_argv)
|
|||||||
chtype oldch = inch();
|
chtype oldch = inch();
|
||||||
unsigned char oldc = oldch & A_CHARTEXT;
|
unsigned char oldc = oldch & A_CHARTEXT;
|
||||||
exit_early = (unsigned char)c != oldc;
|
exit_early = (unsigned char)c != oldc;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (!first_screen && !exit_early && (flags & WATCH_EQUEXIT)) {
|
||||||
|
buffer_size++;
|
||||||
|
#ifdef WITH_WATCH8BIT
|
||||||
|
cchar_t oldc;
|
||||||
|
in_wch(&oldc);
|
||||||
|
if ((wchar_t) c == oldc.chars[0])
|
||||||
|
unchanged_buffer++;
|
||||||
|
#else
|
||||||
|
chtype oldch = inch();
|
||||||
|
unsigned char oldc = oldch & A_CHARTEXT;
|
||||||
|
if ((unsigned char)c == oldc)
|
||||||
|
unchanged_buffer++;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (flags & WATCH_DIFF) {
|
if (flags & WATCH_DIFF) {
|
||||||
@ -753,7 +772,6 @@ static int run_command(char *restrict command, char **restrict command_argv)
|
|||||||
|
|
||||||
fclose(p);
|
fclose(p);
|
||||||
|
|
||||||
|
|
||||||
/* harvest child process and get status, propagated from command */
|
/* harvest child process and get status, propagated from command */
|
||||||
if (waitpid(child, &status, 0) < 0)
|
if (waitpid(child, &status, 0) < 0)
|
||||||
xerr(8, _("waitpid"));
|
xerr(8, _("waitpid"));
|
||||||
@ -771,6 +789,10 @@ static int run_command(char *restrict command, char **restrict command_argv)
|
|||||||
exit(8);
|
exit(8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unchanged_buffer == buffer_size && (flags & WATCH_EQUEXIT))
|
||||||
|
exit_early = 1;
|
||||||
|
|
||||||
first_screen = 0;
|
first_screen = 0;
|
||||||
refresh();
|
refresh();
|
||||||
return exit_early;
|
return exit_early;
|
||||||
@ -780,6 +802,8 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
int optc;
|
int optc;
|
||||||
double interval = 2;
|
double interval = 2;
|
||||||
|
int max_cycles = 1;
|
||||||
|
int cycle_count = 0;
|
||||||
char *interval_string;
|
char *interval_string;
|
||||||
char *command;
|
char *command;
|
||||||
char **command_argv;
|
char **command_argv;
|
||||||
@ -799,6 +823,7 @@ int main(int argc, char *argv[])
|
|||||||
{"beep", no_argument, 0, 'b'},
|
{"beep", no_argument, 0, 'b'},
|
||||||
{"errexit", no_argument, 0, 'e'},
|
{"errexit", no_argument, 0, 'e'},
|
||||||
{"chgexit", no_argument, 0, 'g'},
|
{"chgexit", no_argument, 0, 'g'},
|
||||||
|
{"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-title", no_argument, 0, 't'},
|
{"no-title", no_argument, 0, 't'},
|
||||||
@ -820,7 +845,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::ghn:pvtwx", longopts, (int *)0))
|
getopt_long(argc, argv, "+bced::ghq:n:pvtwx", longopts, (int *)0))
|
||||||
!= EOF) {
|
!= EOF) {
|
||||||
switch (optc) {
|
switch (optc) {
|
||||||
case 'b':
|
case 'b':
|
||||||
@ -840,6 +865,10 @@ int main(int argc, char *argv[])
|
|||||||
case 'g':
|
case 'g':
|
||||||
flags |= WATCH_CHGEXIT;
|
flags |= WATCH_CHGEXIT;
|
||||||
break;
|
break;
|
||||||
|
case 'q':
|
||||||
|
flags |= WATCH_EQUEXIT;
|
||||||
|
max_cycles = strtod_nol_or_err(optarg, _("failed to parse argument"));
|
||||||
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
show_title = 0;
|
show_title = 0;
|
||||||
break;
|
break;
|
||||||
@ -955,9 +984,18 @@ int main(int argc, char *argv[])
|
|||||||
output_header(command, interval);
|
output_header(command, interval);
|
||||||
#endif /* WITH_WATCH8BIT */
|
#endif /* WITH_WATCH8BIT */
|
||||||
|
|
||||||
if (run_command(command, command_argv))
|
int exit = run_command(command, command_argv);
|
||||||
|
if (flags & WATCH_EQUEXIT) {
|
||||||
|
if (cycle_count == max_cycles && exit) {
|
||||||
|
break;
|
||||||
|
} else if (exit) {
|
||||||
|
cycle_count++;
|
||||||
|
} else {
|
||||||
|
cycle_count = 0;
|
||||||
|
}
|
||||||
|
} else if (exit) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (precise_timekeeping) {
|
if (precise_timekeeping) {
|
||||||
watch_usec_t cur_time = get_time_usec();
|
watch_usec_t cur_time = get_time_usec();
|
||||||
|
Loading…
Reference in New Issue
Block a user