I'd like to pass some selected text in a buffer to a python script. The python script will process the string and print the result to stdout. This output should replace the original string that was selected. Can this be done?

To tackle this, I first pass a selected buffer to my python script. Below is the elisp function that I wrote, following a similar function to implement the command wc

(defun it ()
  (shell-command (concat "echo "
                         (buffer-substring (mark) (point))
                         " | /Users/john/bin/t ")))

This command succeeds and prints the output in the mini-buffer. Is there an elisp-way to overwrite the selected text with this output?

  • Just a comment, for a full buffer you can just use (buffer-string), but I understand the current code is more suitable for what you finally intend to do. I think it is nicer if you format the code in different lines b.t.w., I edit you question and do it for you Commented May 31, 2021 at 6:15
  • 1
    Would shell-command-on-region, bound to M-| fit your requirements?
    – rsp
    Commented May 31, 2021 at 8:40
  • rsp's comment provides a better answer than my answer below. I was not aware of shell-command-on-region. I guess it would be handy to put it in an answer instead of a comment... Commented May 31, 2021 at 9:29
  • ok, I added the comment as answer.
    – rsp
    Commented May 31, 2021 at 10:13

2 Answers 2


Would shell-command-on-region, using a prefix argument fit your requirements? shell-command-on-region is by default bound to M-| (Meta key with '|' key) and the prefix argument is by default bound to C-u (Control 'u').

Combining those you can use the key sequence C-u M-| (Control 'u' followed by Meta '|') to pipe a region of text to a command and replace the region with the output of the command.

It asks for the command to pipe the selected text to, in your example that would be /Users/john/bin/t, and runs that command with the selected text on standard input.

  • Please consider showing some code, to illustrate what you suggest.
    – Drew
    Commented May 31, 2021 at 15:06
  • My suggestion is to use the shell-command-on-region command to fulfil the OP's goal (instead of trying to fix the elisp function listed).
    – rsp
    Commented May 31, 2021 at 15:46
  • @rsp can you explain how to use a prefix argument when executing shell-command-on-region? Also, what does binding to C-u M-| mean?
    – linuxfan
    Commented May 31, 2021 at 16:45
  • @linuxfan, updated the answer with some more explanation.
    – rsp
    Commented May 31, 2021 at 17:15

This is perfectly possible and you are almost there. For example to replace e.g. the command/selected text ls in a buffer you can use:

(defun replace-region-from-shell-output ()
  (let ((command-output (shell-command-to-string (buffer-substring (mark) (point)))))
    (kill-region (mark) (point))
    (insert command-output)))
  • rsp's comment provides a better answer. I was not aware of shell-command-on-region Commented May 31, 2021 at 9:27

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.