0

This is probably just a reflection of my weak elisp skills but when I try to create a restclient variable via a function call:

:uid := (shell-command "uuidgen" t)

It does not assign the output of the function call to the variable :uid but rather just outputs the result of the call into the buffer.

Is there some other elisp function I should be wrapping around that shell-command call?

1
  • The accepted answer is very good and helped me. One restclient-related note however. I discovered that when you set a variable like this in restclient the elisp code is run each time you make a request. In the case of uuidgen the result of the call is different each time so your variable will not be the same if you are using it in more than one call.
    – stand
    Oct 18, 2021 at 17:26

1 Answer 1

1

You should read the built–in help for the shell-command function. Type C-h f shell-command and hit enter to pull it up. Specifically, it says this:

The optional second argument OUTPUT-BUFFER, if non-nil,
says to put the output in some other buffer.
If OUTPUT-BUFFER is a buffer or buffer name, erase that buffer
and insert the output there; a non-nil value of
shell-command-dont-erase-buffer prevents the buffer from being
erased.  If OUTPUT-BUFFER is not a buffer and not nil (which happens
interactively when the prefix argument is given), insert the
output in current buffer after point leaving mark after it.  This
cannot be done asynchronously.

Your choices for this argument are to leave it unspecified, to specify nil, t, a string containing a buffer name, or an actual buffer object. When you specify t you are telling it to write the output to the current buffer. You want to put the result into a string instead, so you should make a temporary buffer, change to that new buffer, call shell-command, and then get the contents of the buffer as a string and delete the temporary buffer. Thankfully this kind of situation is fairly common, so in practice you don’t have to do all of that work yourself.

The function buffer-string gets the contents of the current buffer, and with-temporary-buffer runs any code in a new empty buffer that will vanish as soon as the code finishes running. Here’s how to put them together:

(with-temp-buffer
  (shell-command "uuidgen" t)
  (buffer-string))

However, one way of doing things is not enough, so there is also a slightly different way:

(with-output-to-string
  (shell-command "uuidgen" standard-output))

The difference here is that with-output-to-string expects the commands you run to put their output in the buffer stored in the standard-output variable. shell-command doesn’t have a short way of doing that, so we have to specify it ourselves. On the other hand, it calls buffer-string for us. Pick whichever you prefer.

Also, I should point out that you could also use the call-process function in place of shell-command. call-process doesn’t start a shell to run your command in. Since you’re not using any shell features like pipelines, loops, or variables, this is an efficiency gain. Whether that gain is minor or major depends on your exact use case. The arguments are slightly different though:

(with-output-to-string
  (call-process "uuidgen" nil standard-output))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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