In vi[m] there is the !
command which lets me pipe text through a shell command -- like sort or indent -- and get the filtered text back into the buffer. Is there an equivalent in emacs?

- 30,334
- 10
- 78
- 137

- 7,449
- 9
- 45
- 55
-
Just a bit off tangent, I think Vim doesn't have the M-| equivalent of Emacs, Vim can only replace the region with shell output; unless you write custom command for it, I was a bit disappointed. – Arktik Jan 03 '20 at 18:16
3 Answers
You can select a region and type `C-u M-| command RET', and it replaces the region with the command output in the same buffer due to the interactive prefix argument of shell-command-on-region.

- 2,744
- 1
- 22
- 15
-
3Jurta for the win. Upvote. I swear that every time I think I'm starting to know this program, someone comes along and shows me that I'm a rank beginner. – dmckee --- ex-moderator kitten Oct 16 '08 at 00:29
-
Usually when you need a feature in Emacs then chances are that it is already implemented long ago. So the best thing to do first is to read the documentation instead of starting to reinvent the wheel ;) – link0ff Oct 16 '08 at 00:38
-
1Thanks jurta. Unfortunately I couldn't find any documentation for this feature. – Rohit Oct 16 '08 at 05:46
-
2Rohit, you can find its documentation in Emacs by opening the Emacs manual (`C-h i d m Emacs RET') and looking for the command name in the index - `i shell-command-on-region RET'. – link0ff Oct 16 '08 at 11:09
-
4This is good for using "perl pie" to do regular expression search & replace when Emacs Regexp isn't quite cutting it. `C-u M-| perl -pi -e 's/pattern/replace/g' RET`. Evil supports the Vim command for doing this too (`:%!perl -pi -e ... RET`). – d11wtq May 18 '13 at 16:29
I wrote this a few years back, it might help you:
(defun generalized-shell-command (command arg)
"Unifies `shell-command' and `shell-command-on-region'. If no region is
selected, run a shell command just like M-x shell-command (M-!). If
no region is selected and an argument is a passed, run a shell command
and place its output after the mark as in C-u M-x `shell-command' (C-u
M-!). If a region is selected pass the text of that region to the
shell and replace the text in that region with the output of the shell
command as in C-u M-x `shell-command-on-region' (C-u M-|). If a region
is selected AND an argument is passed (via C-u) send output to another
buffer instead of replacing the text in region."
(interactive (list (read-from-minibuffer "Shell command: " nil nil nil 'shell-command-history)
current-prefix-arg))
(let ((p (if mark-active (region-beginning) 0))
(m (if mark-active (region-end) 0)))
(if (= p m)
;; No active region
(if (eq arg nil)
(shell-command command)
(shell-command command t))
;; Active region
(if (eq arg nil)
(shell-command-on-region p m command t t)
(shell-command-on-region p m command)))))
I've found this function to be very helpful. If you find it useful as well, I suggest binding it to some function key for convenience, personally I use F3
:
(global-set-key [f3] 'generalized-shell-command)

- 33,090
- 15
- 73
- 105
-
Excellent. This acts just like joe's "C-k /" pipe through shell command. – Barry Kelly Sep 21 '13 at 18:46
Late edit: As much as I appreciate the upvotes, Jurta's answer is the way to go. And Greg's hack is neater than mine.
I'll leave the rest of this here because it might be worth something, but...
M-x shell-command-on-region
, which appears to be bound to M-|
by default.
I see that this does not do exactly what Rohit asked for. Using C-h f shell-command-on-region
reveals that the desired behavior is available in the non-interactive version of the command (by setting the argument replace
to non-nil). We should be able to write a wrapper to do this.
Try this (load it into *scratch*
and run M-x eval-buffer
, if it works, copy it to your .emacs file):
(defun shell-command-on-region-replace (start end command)
"Run shell-command-on-region interactivly replacing the region in place"
(interactive (let (string)
(unless (mark)
(error "The mark is not set now, so there is no region"))
;; Do this before calling region-beginning
;; and region-end, in case subprocess output
;; relocates them while we are in the minibuffer.
;; call-interactively recognizes region-beginning and
;; region-end specially, leaving them in the history.
(setq string (read-from-minibuffer "Shell command on region: "
nil nil nil
'shell-command-history))
(list (region-beginning) (region-end)
string)))
(shell-command-on-region start end command t t)
)
And note as I say in the comments that this is not a very emacsy thing to do. But I think it works.
For any readers who don't know how to select a region:
- Move the "point" (current cursor position) to one end of the region, and use
C-space
to activate the "mark" - Move the point to the other end of the region
- Your done, invoke the command

- 98,632
- 24
- 142
- 234
-
Thank you, I know of that, but it gives me the filtered text in a separate buffer; it doesn't replace the original. – Rohit Oct 15 '08 at 22:47
-
I know the vi behavior you want. Still looking. – dmckee --- ex-moderator kitten Oct 15 '08 at 23:05
-
Interesting that this is not simply a FAQ. I use this functionality in vi (or vim) all the time; an editor without it becomes ... less interesting. – Jonathan Leffler Oct 15 '08 at 23:30
-
I use this behavior in vi, too, but it is not the emacs way, which would probably be to define a mode that knows what you want and let it happen automatically. – dmckee --- ex-moderator kitten Oct 15 '08 at 23:42
-
-
Since you mention selecting a region. `C-x h` selects the whole buffer, which often comes in handy. I just used it in this case. – Stéphane Gourichon Jul 09 '13 at 11:01
-
If you accidentally run `shell-command-on-region` without the `C-u` prefix, you can still copy the output of the command from the `*Messages*` buffer. – MatthewD Sep 10 '15 at 01:42
-
This is very good. Does anyone know how to use the C-u prefix in evil mode? – Martin May 03 '19 at 09:15