在 Emacs 中通过 shell 命令过滤文本

在 vi [ m ]中,通过一个 shell 命令(如 sort 或 indent)使用 !命令,它允许我管道文本,并将经过筛选的文本返回到缓冲区。在 emacs 中有一个等价物吗?

15845 次浏览

后期编辑 : 虽然我很感激你们的赞同,但 Jurta 的回答才是正确的选择。格雷格的黑客技术比我的好多了。

我把剩下的留在这里,因为它可能值点钱,但是..。


M-x shell-command-on-region ,默认情况下似乎绑定到 M-|


我发现这并不完全符合 Rohit 的要求。使用 C-h f shell-command-on-region表明在非交互式版本的命令中可以获得所需的行为(通过将参数 replace设置为非 nil)。我们应该能够编写一个包装器来完成这项工作。

尝试这样做(将其加载到 *scratch*并运行 M-x eval-buffer,如果可行,将其复制到. emacs 文件中) :

(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)
)

请注意,我在评论中说,这不是一个非常容易做到的事情。不过我觉得挺管用的。


对于那些不知道如何选择地区的读者:

  1. 将“点”(当前光标位置)移动到区域的一端,并使用 C-space激活“标记”
  2. 将该点移动到区域的另一端
  3. 你完成了,调用命令

您可以选择一个区域并键入‘ C-u M-| command RET’,由于 shell-command-on-region 的交互式前缀参数,它将该区域替换为同一缓冲区中的命令输出。

我几年前写过这个,可能对你有帮助:

(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)))))

我发现这个函数非常有用。如果你发现它也很有用,我建议将它绑定到某个函数键上,以方便使用,我个人使用 F3:

(global-set-key [f3] 'generalized-shell-command)