5

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?

2
6

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
0
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"))'
4
  • 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 1 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 4 at 0:05
  • 1
    Thank you @ebpa. – grettke Apr 4 at 23:25

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.