6

I want to use emacsclient to let my running instance of emacs evaluate a function and print the result to a terminal.

That is, I want to do something like this:

$ emacsclient --eval "(frame-parameter (car (frame-list)) 'name)"
*info*

However, instead, I get output like this:

"*info*"

If I use message, the output is displayed in some frame's minibuffer and I still get quoted output ("*info*" instead of *info*).

How do I get princ-like output to be output to my emacsclient terminal?

Drew
  • 75,699
  • 9
  • 109
  • 225
Colin Fraizer
  • 740
  • 4
  • 12
  • Use `message`? Your code prints the result of evaluation, which is a string. `message` formats stdout stream. – wvxvw Nov 15 '16 at 10:39
  • See also [Why is Emacsclient inserting quotes around output strings?](http://emacs.stackexchange.com/q/9391/260) – Håkon Hægland Nov 15 '16 at 18:53

2 Answers2

7

It seems that emacsclient is the wrong way to do what I want. I thought I could not use emacs --batch because I wanted to get "live" info from my running emacs instance.

The missing piece of the puzzle was the function server-eval-at:

$ emacs --batch --eval "(progn (require 'server) (princ (format \"%s\\n\" (server-eval-at \"server\" '(frame-parameter (car (frame-list)) 'name)))))"
*info*

Or, a more significant example:

$ emacs --batch --eval "(progn (require 'server) (princ (format \"%s\\n\" (server-eval-at \"server\" '(mapconcat (lambda (f) (frame-parameter f 'name)) (frame-list) \"\\n\")))))"
*info*
CAPTURE-3-foo-service.org
SomeClass.java
SomeOtherClass.java
Colin Fraizer
  • 740
  • 4
  • 12
0

AFAIK it is not possible to redirect standard output from an emacs server directly with emacsclient alone. As you found, the only output of is the value that the s-expression evaluates to. server-eval-at with emacs --batch --eval looks like a good option. If you still want to use emacsclient for some reason, here's one approach that will work for capturing standard output. I'm not sure how to capture standard error in this manner.

Since emacsclient --eval does not capture any of the server's standard output streams, you will need to capture it as part of your s-expression:

emacsclient --eval "(with-output-to-string\
  (mapc\
   (lambda (frame)\
     (princ (format \"%s\\n\" (frame-parameter frame 'name))))\
   (frame-list)))"

Anything printed to standard output during within the body of with-output-to-string is captured and returned as a string value. You can then print that string output as Emacs otherwise (by using Emacs to interpret it):

emacsclient --eval '(with-output-to-string \
  (mapc \
   (lambda (frame) \
     (princ (format "%s\\n" (frame-parameter frame \'name)))) \
   (frame-list)))' \
| emacs --batch --eval '(princ \
  (concat \
    (with-temp-buffer \
      (insert-file-contents "/dev/stdin") \
      (read (current-buffer))) \
    "\n"))'

The same command (in one line):

emacsclient --eval '(with-output-to-string (princ "Hello, World!"))' | emacs --batch --eval '(princ (concat (with-temp-buffer (insert-file-contents "/dev/stdin") (read (current-buffer))) "\n"))'
ebpa
  • 7,319
  • 26
  • 53
  • Thanks! I am using emacsclient because I want to get information about my running emacs process. `epipe` might be a good solution. I'm not sure `make-symbol` is right for what I want. Imagine I want output like "You have 37 buffers:\n- 2 are elisp-mode\n- 2 are info-mode\n...". – Colin Fraizer Nov 15 '16 at 15:33
  • Would using `server-eval-at` within the same server that `emacsclient` return the same or different information? – grettke Apr 01 '21 at 23:23
  • 2
    @grettke you can use both `emacsclient --eval` and `server-eval-at` to invoke an s-expression in a particular emacs server. Note my answer about how standard output and standard error are not printed by `emacsclient --eval`. – ebpa Apr 04 '21 at 00:05
  • 1
    Thank you @ebpa. – grettke Apr 04 '21 at 23:25
  • When I use the example above with Emacs 29, piping to `emacs --batch ...` to unquote, I get `Maximum buffer size exceeded`. I have to set the `END` argument of `insert-file-contents` to some reasonable value to make it work. I have written up a bit more in https://www.reddit.com/r/emacs/comments/asil1y/comment/jm3r2a6/ -- hope that helps someone, but also grateful for any more elegant solutions. – Charl Botha May 29 '23 at 18:58