2

Suppose that I have a *shell* buffer (i.e. a subordinate shell, started with M-x shell). Suppose also that at this shell's prompt, I can execute some command foo that sends some output to stdout.

I know that, in general, I can always select the region in the *shell* buffer corresponding to foo's output and add it to the kill-ring with C-w.

I'd like, however, to pipe foo's output directly to the kill-ring, so that it never appears in the *shell* buffer (and thus obviating the need to select the appropriate region and run C-w).

Is there a way to do this?

For example, is there some Unix command bar such that running

% foo | bar 

...in the *shell* buffer will cause the output of foo to be added to Emacs's kill-ring?


In case there's a difference between them, I'd like to know the answer to this question for 3 different cases (in order of importance):

  1. Emacs is running as an X11 application (Debian Linux + Xfce4 + Xfwm4);
  2. Emacs is running in "text-only mode" (e.g. started with emacs -nw);
  3. Emacs is running as a Cocoa application in OS X (i.e. it is /Applications/Emacs.app, installed from here);

PS: I just learned that eshell (not to be confused with M-x shell/comint) implements the /dev/kill pseudo-file, which solve's this post's problem (i.e. foo > /dev/kill adds foo's output to the kill-ring). Unfortunately, IME, using eshell has always been an absolute nightmare, since so little of what I know from bash works with eshell; I don't want to learn a whole new---and totally weird--shell from the bottom up just to solve this post's problem. Therefore, at the moment at least, eshell-based solutions are out of the question. This may change, however, depending on the answers I get to another question I just posted.

1
  • I came here looking for the /dev/kill eshell thing. Thanks for your edit at the bottom! Commented Nov 13, 2018 at 18:23

1 Answer 1

6

Emacs Command

Instead of select-and-copy manually, you can also write a command and let it do the work for you:

;; Adapted from `comint-delete-output' (defun comint-copy-output () "Copy all output from interpreter since last input." (interactive) (let ((proc (get-buffer-process (current-buffer)))) (save-excursion (let ((pmark (progn (goto-char (process-mark proc)) (forward-line 0) (point-marker)))) (kill-new (buffer-substring comint-last-input-end pmark)))))) 

foo | bar

Your idea can also be achieved by a simple shell script. It assumes Emacs server is running, if it is not, you can start it via the command server-start or run Emacs as a daemon.

#!/bin/bash cat /dev/stdin > /tmp/clip emacsclient --eval '(kill-new (my-file-contents "/tmp/clip"))' 

Becuase it's not easy to embedding Lisp code in shell, my-file-contents is defined in Emacs.

(defun my-file-contents (file) (with-temp-buffer (insert-file-contents file) (buffer-string))) 

Now in shell, % foo | bar should do what you want (assuming bar is the shell script and it is in your PATH).

foo > /tmp/kill

In Eshell, you can save output to the kill ring by redirecting output to /dev/kill. You can do the similar in any shell:

  1. redirect output to /tmp/kill
  2. when the contents of /tmp/kill changes, make Emacs copies the new contents to the kill ring

(notes that your Emacs should be compiled with support of watching filesystem, I guess it means (require 'filenotify) should return non-nil)

(defun save-to-kill-ring-if-changes (event) ;; (message "Event %S" event) (when (eq (cadr event) 'changed) (kill-new (my-file-contents "/tmp/kill")))) ;; Create /tmp/kill firstly (write-region "" nil "/tmp/kill") (file-notify-add-watch "/tmp/kill" '(change) 'save-to-kill-ring-if-changes) 

then in any shell, % foo > /tmp/kill should copy the output of foo to the kill ring.

1
  • FYI the file path is /dev/kill , not /tmp/kill Commented Sep 10, 2024 at 17:25

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.