M-|
(M-x shell-command-on-region
) runs a shell command using the region as stdin, display the output in the echo area, with a prefix arg, replace the region with the output.
Unlike your shell in a terminal, each use of M-!
or M-|
: start a shell such as bash
, run the shell command, then kill the shell. And the region is data passed to the shell command, the content is arbitrary, for example,
ABCDE M-| wc
{"type": "JSON"} M-| jq
the above works because wc
and jq
read stdin as input, and since the executables bash
, ruby
and python3
read stdin as corresponding programming code, you can run Bash/Ruby/Python code with M-|
, e.g.,
echo "Bash" M-| bash
puts "Ruby" M-| ruby
print("Python") M-| python3
In other words, M-|
is simple and generic, so stick with it, if you need insert the output, simply copy-and-paste, though defining your own command isn't hard at all, e.g.,
(defun your-shell-command-on-region ()
"Like `shell-command-on-region' but insert output after the region."
(declare (interactive-only t))
(interactive)
(let ((output-buffer (generate-new-buffer " *temp*")))
(shell-command-on-region
(region-beginning) (region-end)
(read-shell-command "Shell command on region: ")
output-buffer)
(goto-char (region-end))
(unless (bolp)
(insert ?\n))
(insert-buffer-substring output-buffer)
(kill-buffer output-buffer)))
Run current line or selection in shell then insert result in buffer in Emacs
Let's assuming the current line or selection are shell code
(defun $ (b e)
"Run current line or selection in shell and insert output."
(interactive
(if (use-region-p)
(list (region-beginning) (region-end))
(list (line-beginning-position) (line-end-position))))
(save-excursion
(goto-char e)
(unless (bolp) (insert "\n"))
(shell-command (buffer-substring-no-properties b e) t t)))
(global-set-key (kbd "C-c C-c") #'$)
A cool idea is update the output in-place (like Org Mode Babel), that is, delete the old output then insert the new output,
(defun $$ (b e)
"Run current line as shell code and insert/update output."
(interactive (list (line-beginning-position)
(line-end-position)))
(save-excursion
;; delete old output
(delete-region
(progn (forward-line) (point))
(progn (while (get-text-property (point) '$$)
(forward-line))
(point)))
(unless (bolp) (insert "\n"))
(let* ((command (buffer-substring-no-properties b e))
(output (with-temp-buffer
(shell-command command t t)
(buffer-string)))
(start (point)))
(insert (propertize output '$$ t 'rear-nonsticky t))
(pulse-momentary-highlight-region start (point)))))
Try it with date
.
Ultimately, I'd like to embed an acme-like workflow into Emacs, where I can put a few short commands on an anchored top line, then run them while providing a selected text as input to the said command,
M-|
does this, though the user interface is different, the input is from the region, the command is from the minibuffer, the output is to echo area.
To implement the similar workflow you described, get started with three buffers for input/command/output, the code should be straightforward.