12

Does watch only monitor the visible output of a command? Say I'm in a directory with the following contents:

$ ls
a  b  c  d  e  f  g  h  i  j  k  l  m  n

If I run watch -g ls -1 I expect it to exit if a file is added or removed. What actually happens is that it exits only if the file in question is visible in the terminal output of watch:

$ watch -g ls -1
Every 2.0s: ls -1                   Wed Nov 13 16:35:03 2013

a
b
c
d
e
f

Deleting the file m, which is not visible because of the size of my terminal, does nothing. Deleting a visible file, say d, causes watch to exit as expected.

The -g flag is explained thusly in my man page:

   -g, --chgexit
          Exit when the output of command changes.

What's going on? Is this normal? How can I use watch for commands with long output? I am using watch from procps-ng 3.3.4 which was installed from the Debian repos.

  • What does the -g option to watch do? I don't find it in my version of watch – iruvar Nov 13 '13 at 16:09
  • @1_CR see updated question, it should cause it to exit when the output changes. It does work as advertised when the change is visible on the screen. – terdon Nov 13 '13 at 16:18
9

I found this thread titled: Bug#225549: have watch monitor stderr. That thread is from 2008, but it looks like older versions don't support the watching of anything other than STDOUT.

So we're limited to just STDOUT. As for visible there is a lot of language in the info watch and man watch that make me think your observation/assumption is correct.

excerpt

   watch runs command repeatedly, displaying its output (the first screen‐
   full).   This  allows you to watch the program output change over time.
   By default, the program is run every 2 seconds; use -n or --interval to
   specify a different interval.

Also this bit under BUGS:

BUGS
       Upon  terminal resize, the screen will not be correctly repainted until
       the next scheduled update.  All --differences highlighting is  lost  on
       that update as well.

If I had to guess I'd think they were storing the visible bits in a buffer between runs, and then analyzing just those characters.

EDIT #1

I debugged this further using strace and you can see watch reading the output from the ls command so it's internally dropping the change.

before I delete the m file

$ strace -o w.log watch -g 'ls -1'
read(3, "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\nw.lo"..., 4096) = 34
close(3)                                = 0
--- SIGCHLD (Child exited) @ 0 (0) ---
munmap(0x7f4da83af000, 4096)            = 0
wait4(31011, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 31011
rt_sigaction(SIGTSTP, {SIG_IGN, [], SA_RESTORER|SA_RESTART, 0x7f4da79b94a0}, {0x7f4da7f81ee0, [], SA_RESTORER|SA_RESTART, 0x7f4da79b94a0}, 8) = 0
write(1, "\33[H\33[2JEvery 2.0s: ls -1\33[1;140H"..., 119) = 119
rt_sigaction(SIGTSTP, {0x7f4da7f81ee0, [], SA_RESTORER|SA_RESTART, 0x7f4da79b94a0}, NULL, 8) = 0
nanosleep({2, 0}, NULL)                 = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=3519, ...}) = 0
pipe([3, 4])                            = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f4da839f9d0) = 31014
close(4)                                = 0
fcntl(3, F_GETFL)                       = 0 (flags O_RDONLY)
fstat(3, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4da83af000
lseek(3, 0, SEEK_CUR)                   = -1 ESPIPE (Illegal seek)
read(3, "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\nw.lo"..., 4096) = 34
close(3)                                = 0
munmap(0x7f4da83af000, 4096)            = 0
--- SIGCHLD (Child exited) @ 0 (0) ---

after the m file is deleted

--- SIGCHLD (Child exited) @ 0 (0) ---
rt_sigaction(SIGTSTP, {SIG_IGN, [], SA_RESTORER|SA_RESTART, 0x7f4da79b94a0}, {0x7f4da7f81ee0, [], SA_RESTORER|SA_RESTART, 0x7f4da79b94a0}, 8) = 0
poll([{fd=0, events=POLLIN}], 1, 0)     = 0 (Timeout)
poll([{fd=0, events=POLLIN}], 1, 0)     = 0 (Timeout)
write(1, "\33[1;158H8\33[11;163H", 18)  = 18
rt_sigaction(SIGTSTP, {0x7f4da7f81ee0, [], SA_RESTORER|SA_RESTART, 0x7f4da79b94a0}, NULL, 8) = 0
nanosleep({2, 0}, NULL)                 = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=3519, ...}) = 0
pipe([3, 4])                            = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f4da839f9d0) = 31028
close(4)                                = 0
fcntl(3, F_GETFL)                       = 0 (flags O_RDONLY)
fstat(3, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4da83af000
lseek(3, 0, SEEK_CUR)                   = -1 ESPIPE (Illegal seek)
read(3, "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nn\nw.log\n", 4096) = 32
close(3)                                = 0
--- SIGCHLD (Child exited) @ 0 (0) ---
munmap(0x7f4da83af000, 4096)            = 0
wait4(31028, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 31028
  • Yeah, it just seems weird, it makes it impossible to run something like watch -g foo; echo "Something changed!". It seems a strangely crippling bug in such an established program. – terdon Nov 14 '13 at 1:50
  • @terdon - my ancient version of Fedora didn't have the -g switch but I tried it on Ubuntu and it behaves the same. – slm Nov 14 '13 at 2:19
  • OK, that's really weird then. So it does actually monitor and see the change, it just doesn't react to it! Definitely a bug then. – terdon Nov 14 '13 at 12:15
2

I expect it to exit if a file is added or removed

I'm pretty sure you're after inotify-tools.

My manpage for watch, from procps-ng, says

watch runs command repeatedly, displaying its output and errors (the first screenfull).

  • That's not what he's asking about, he's trying to understand the behavior of an update occurring, being displayed via STDOUT, but isn't visible in the terminal b/c he's re-sized it so that the output that is being changed is "off screen". Most everyone I've discussed this with today would've expected watch to behave as the OP, and exit with the change. – slm Nov 14 '13 at 7:06
  • Yes we've already discussed that too, I highlighted that same text in my answer. I know Terdon fairly well and at this point he wants to know the reason why. – slm Nov 14 '13 at 7:32
  • I agree it's not the answer to his question, but it's the solution to his problem. – jthill Nov 14 '13 at 7:33
  • You mean using inotify? That's not what he's after, he wants to know why watch behaves this way. He knows about inotify. – slm Nov 14 '13 at 7:34
  • That's his question. What he's trying to do with it is what I quoted: wait for a file to be added or removed. Watch isn't the tool for that job. – jthill Nov 14 '13 at 7:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.