This problem has been annoying me for a while. So I wrote a patch. The attached patch provides an option for watch to monitor stderr as well as stdout. [I think that behavior should be the default, but for now, I've just made it an option.] It also provide an option for watch to beep if the command fails.
I emailed it to the procps feedback list a couple of days ago, and haven't heard back yet. So I decided to open a debian bug for tracking purposes. . . and found there already are a bunch. Looks like 481679 is also a dup of this bug. - Morty
Binary files procps-3.2.7-orig/.watch.c.swp and procps-3.2.7/.watch.c.swp differ diff -Nur procps-3.2.7-orig/watch.1 procps-3.2.7/watch.1 --- procps-3.2.7-orig/watch.1 2003-02-09 02:05:25.000000000 -0500 +++ procps-3.2.7/watch.1 2008-08-06 07:01:05.000000000 -0400 @@ -3,7 +3,7 @@ watch \- execute a program periodically, showing output fullscreen .SH SYNOPSIS .B watch -.I [\-dhvt] [\-n <seconds>] [\-\-differences[=cumulative]] [\-\-help] [\-\-interval=<seconds>] [\-\-no\-title] [\-\-version] <command> +.I [\-bdhvst] [\-n <seconds>] [\-\-beep] [\-\-differences[=cumulative]] [\-\-errors-too] [\-\-help] [\-\-interval=<seconds>] [\-\-no\-title] [\-\-version] <command> .SH DESCRIPTION .BR watch runs @@ -28,7 +28,15 @@ or .I --no-title option turns off the header showing the interval, command, and current -time at the top of the display, as well as the following blank line. +time at the top of the display, as well as the following blank line. The +.I -b +or +.I --beep +option causes the command to beep if it has a non-zero exit. The +.I -s +or +.I --errors-too +option causes error output to be handled just like normal output. .PP .BR watch will run until interrupted. @@ -84,4 +92,5 @@ .B watch was written by Tony Rems <[EMAIL PROTECTED]> in 1991, with mods and corrections by Francois Pinard. It was reworked and new features added by -Mike Coleman <[EMAIL PROTECTED]> in 1999. +Mike Coleman <[EMAIL PROTECTED]> in 1999. The beep and errors-too features were +added by Morty Abzug <[EMAIL PROTECTED]> in 2008. diff -Nur procps-3.2.7-orig/watch.c procps-3.2.7/watch.c --- procps-3.2.7-orig/watch.c 2006-06-17 05:18:38.000000000 -0400 +++ procps-3.2.7/watch.c 2008-08-06 07:06:06.000000000 -0400 @@ -8,6 +8,7 @@ * Mike Coleman <[EMAIL PROTECTED]>. * * Changes by Albert Cahalan, 2002-2003. + * errors-too and beep options added by Morty Abzug, 2008 */ #define VERSION "0.2.0" @@ -35,13 +36,15 @@ {"differences", optional_argument, 0, 'd'}, {"help", no_argument, 0, 'h'}, {"interval", required_argument, 0, 'n'}, + {"errors-too", no_argument, 0, 's'}, + {"beep", no_argument, 0, 'b'}, {"no-title", no_argument, 0, 't'}, {"version", no_argument, 0, 'v'}, {0, 0, 0, 0} }; static char usage[] = - "Usage: %s [-dhntv] [--differences[=cumulative]] [--help] [--interval=<n>] [--no-title] [--version] <command>\n"; + "Usage: %s [-bdhnstv] [--beep] [--differences[=cumulative]] [--errors-too] [--help] [--interval=<n>] [--no-title] [--version] <command>\n"; static char *progname; @@ -140,17 +143,25 @@ int optc; int option_differences = 0, option_differences_cumulative = 0, + option_errors_too = 0, + option_beep = 0, option_help = 0, option_version = 0; double interval = 2; char *command; int command_length = 0; /* not including final \0 */ + int pipefd[2]; + int status; + pid_t child; setlocale(LC_ALL, ""); progname = argv[0]; - while ((optc = getopt_long(argc, argv, "+d::hn:vt", longopts, (int *) 0)) + while ((optc = getopt_long(argc, argv, "+bd::hn:vst", longopts, (int *) 0)) != EOF) { switch (optc) { + case 'b': + option_beep = 1; + break; case 'd': option_differences = 1; if (optarg) @@ -159,6 +170,9 @@ case 'h': option_help = 1; break; + case 's': + option_errors_too = 1; + break; case 't': show_title = 0; break; @@ -191,11 +205,13 @@ if (option_help) { fprintf(stderr, usage, progname); + fputs(" -b, --beep\t\t\t\tbeep if the command has a non-zero exit\n", stderr); fputs(" -d, --differences[=cumulative]\thighlight changes between updates\n", stderr); fputs("\t\t(cumulative means highlighting is cumulative)\n", stderr); fputs(" -h, --help\t\t\t\tprint a summary of the options\n", stderr); fputs(" -n, --interval=<seconds>\t\tseconds to wait between updates\n", stderr); fputs(" -v, --version\t\t\t\tprint the version number\n", stderr); + fputs(" -s, --errors-too\t\t\tredirects errors as well\n", stderr); fputs(" -t, --no-title\t\t\tturns off showing the header\n", stderr); exit(0); } @@ -261,11 +277,50 @@ free(header); } - if (!(p = popen(command, "r"))) { - perror("popen"); + /* allocate pipes */ + if (pipe(pipefd)<0) { + perror("pipe"); + do_exit(7); + } + + /* flush stdout and stderr, since we're about to do fd stuff */ + fflush(stdout); + fflush(stderr); + + /* fork and exec */ + child=fork(); + + if (child<0) { /* fork error */ + perror("fork"); do_exit(2); + } else if (child==0) { /* in child */ + close (pipefd[0]); + close (1); + if (dup2 (pipefd[1], 1)<0) { + perror("dup2"); + exit(3); + } + if (option_errors_too) { + close(2); + dup2(1, 2); + } + /* this should use execvp, but the watch manpage promises quoting */ + status=system(command); + if (!WIFEXITED(status)) { + exit(1); + } else { + exit(WEXITSTATUS(status)); + } } + /* otherwise, we're in parent */ + close(pipefd[1]); /* close write side of pipe */ + if ((p=fdopen(pipefd[0], "r"))==NULL) { + perror("fdopen"); + do_exit(5); + } + + for (y = show_title; y < height; y++) { int eolseen = 0, tabpending = 0; for (x = 0; x < width; x++) { @@ -313,7 +368,18 @@ oldeolseen = eolseen; } - pclose(p); + fclose(p); + + /* harvest child process and get status */ + if (waitpid(child, &status, 0)<0) { + perror("waitpid"); + do_exit(8); + }; + + /* if child process exited in error, beep */ + if (option_beep && (!WIFEXITED(status) || WEXITSTATUS(status))) { + beep(); + } first_screen = 0; refresh();