The code below calls upon a Python script to generate pinyin from Chinese characters in region:

(defun pinyin ()
  "Generate Pinyin from Chinese Characters with Python script, keeping the original Chinese characters intact."
  (let ((cmdStr
          "python3 -c \"import pinyin; print(pinyin.get(\'%s\', delimiter=\' \'))\""
          (buffer-substring (region-beginning) (region-end)))))
     (format "\n%s"
             (shell-command cmdStr (buffer-file-name))))))

I would like the script to insert the pinyin on a new line under the selected Chinese characters.

The above script correctly displays the desired output in the mini-buffer but inserts 0 at the place where the pinyin should be.

What went wrong and how can I get this working properly?

  • 1
    Use (shell-command cmdStr t) to insert the output of the command at point in the current buffer.
    – NickD
    Commented Jun 15, 2020 at 18:11

1 Answer 1


(buffer-file-name) returns the full pathname of the file visited in the current buffer but that is NOT the name of the buffer, so the output is saved in a different buffer. The name of the current buffer is returned by calling the function buffer-name. But the doc string for shell-command says:

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, insert the output in current buffer after point leaving mark after it. This cannot be done asynchronously.

and I think it is easier to use a non-nil value that is not a buffer for the OUTPUT-BUFFER argument: that way, we "insert the output in current buffer after point leaving mark after it" - and the easiest non-nil value to type is t, so use

(shell-command cmdStr t)

in your function.


(insert (format "\n%s" (shell-command cmdStr t)))

That will format the return value of (shell-command ...), which seems to be nil in my experiments, as a string and insert it in the buffer, before the output of the command.

You should just do:

(let ((cmdStr ...))
  (shell-command cmdStr t))

Not sure why you are getting the value of (region-end) however.

  • Why is the value of (region-end) inserted before my desired output?
    – Sati
    Commented Jun 15, 2020 at 19:53
  • 1
    Because you are inserting the formatted return value of the call to shell-command. I'll edit the answer.
    – NickD
    Commented Jun 15, 2020 at 19:58
  • When I simplify to (insert (shell-command cmdStr t)), t got inserted before the desired value instead. How can the unnecessary insertion be avoided?
    – Sati
    Commented Jun 15, 2020 at 20:07
  • 1
    Do NOT use insert! See my edit.
    – NickD
    Commented Jun 15, 2020 at 20:49

Your Answer

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

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