3

This doesn't seem to work in M-x shell

$ watch 'grep "FIX" /tmp/output | tail -n 5'

I see Every 2.0s: grep "FIX" /tmp/output | tail -n 5 and I see My-hostname.local: Tue Aug 28 19:09:22 2018 on screen.

Whats the emacs way of doing it?

american-ninja-warrior
  • 3,773
  • 2
  • 21
  • 40
  • `watch` will require more than just a dumb terminal, so don't use `M-x shell` for that. Try `M-x term`. – phils Aug 29 '18 at 03:29
  • 4
    BTW, I still think you should consider accepting answers more often if you want to encourage people to spend time writing them. https://emacs.stackexchange.com/users/9829/?tab=questions displays a very low ratio. May I ask why it is that you so rarely accept answers? – phils Aug 29 '18 at 04:16
  • it's because "what if there's a better answer..." line of thinking – american-ninja-warrior Aug 29 '18 at 15:09
  • a lot of emacs kbd shortcuts don't work in M-x term. thats why I don't use it – american-ninja-warrior Aug 29 '18 at 15:10
  • 4
    I guess there can always be a better answer; but you can change which answer is the accepted answer if that happens. In cases where there's a good answer which *does* resolve the issue in a satisfactory way, and "better" answers are not forthcoming, I think it's reasonable to accept it. Waiting a while to see what happens is fine, but voting and accepting are pretty much how people say "thank you for spending your time to help me", so you should review your queue on a somewhat-regular basis, so that you don't appear to be "that rude guy who asks for help and never says thank you". – phils Aug 30 '18 at 06:10
  • @american-ninja-warrior In `M-x term`, if you need normal Emacs key bindings, switch to "line mode". And don't forget to switch back to "char mode" when you need the terminal to handle your keys. – xuchunyang Aug 30 '18 at 11:47

2 Answers2

4

As commented, watch needs to run in a terminal so that it can do all the fancy things that it does. In Emacs, that means running it via term.

The very simplest thing is to invoke it from a shell running in M-x term

You can also run the watch process directly in the terminal, but because the command needs arguments, doing that requires a custom wrapper along the lines of https://emacs.stackexchange.com/a/18678/454. Using the my-terminal-run command in that answer, you could just type your ad-hoc watch command at the prompt (or indeed any other command).

You can also write a wrapper specifically for watch. The following Emacs command has a similar basis to the examples in the linked answer, but adds additional code for trivially dismissing and killing the buffer.

(defvar watch-history nil)
(defun watch (command &optional name)
  "Runs \"watch COMMAND\" in a `term' buffer.  \"q\" to exit."
  (interactive
   (list (read-from-minibuffer "watch " nil nil nil 'watch-history)))
  (let* ((name (or name (concat "watch " command)))
         (switches (split-string-and-unquote command))
         (termbuf (apply 'make-term name "watch" nil switches))
         (proc (get-buffer-process termbuf)))
    (set-buffer termbuf)
    (term-mode)
    (term-char-mode)
    (setq show-trailing-whitespace nil)
    ;; Kill the process interactively with "q".
    (set-process-query-on-exit-flag proc nil)
    (let ((map (make-sparse-keymap))
          (cmdquit (make-symbol "watch-quit")))
      (put cmdquit 'function-documentation "Kill the `watch' buffer.")
      (put cmdquit 'interactive-form '(interactive))
      (fset cmdquit (apply-partially 'kill-process proc))
      (set-keymap-parent map (current-local-map))
      (define-key map (kbd "q") cmdquit)
      (use-local-map map))
    ;; Kill the buffer automatically when the process is killed.
    (set-process-sentinel
     proc (lambda (process signal)
            (and (memq (process-status process) '(exit signal))
                 (buffer-live-p (process-buffer process))
                 (kill-buffer (process-buffer process)))))
    ;; Display the buffer.
    (switch-to-buffer termbuf)))
phils
  • 48,657
  • 3
  • 76
  • 115
  • 1
    Oh, your single-quoting for the shell won't play nice with this wrapper; but you don't need them -- all the arguments are passed to `watch` so just enter `grep "FIX" /tmp/output | tail -n 5` unquoted at the prompt. – phils Aug 30 '18 at 08:48
4

An alternative solution:

(with-eval-after-load 'em-term
  (add-to-list 'eshell-visual-commands "watch"))

To run command like watch -d date, issue:

M-x eshell-command RET watch -d date RET

The watch command requires a terminal emulator, which usually needs control keyboard events by itself, thus most Emacs key bindings will not work. Emacs provides a terminal emulator via M-x term. If you must run commands like watch within Emacs, you have to use it. I don't think you have other choice.

xuchunyang
  • 14,302
  • 1
  • 18
  • 39
  • is there a way to scroll within the `*watch*` buffer? I can't seem to move around point to e.g. kill some text – erjoalgo Oct 09 '18 at 20:17