Emacs-对区域上的shell命令的非交互调用是否始终删除区域?

Emacs-对区域上的shell命令的非交互调用是否始终删除区域?,emacs,elisp,Emacs,Elisp,区域上的函数shell命令的Emacs帮助页面显示(省略空格): 这不是最清楚的,但刚才引用的最后几句话似乎表明,如果我希望shell命令的输出插入当前缓冲区的某个点,而保留缓冲区的其他内容不变,我应该为output-buffer传递一个非nil参数,为REPLACE传递nil参数 但是,如果我在*scratch*缓冲区中执行此代码(不是我正在处理的真实代码,而是演示此问题的最小案例): 缓冲区的全部内容被删除并替换为wc的输出 当以非交互方式使用时,区域上的shell命令是否已损坏,或者我是否

区域上的函数
shell命令的Emacs帮助页面显示(省略空格):

这不是最清楚的,但刚才引用的最后几句话似乎表明,如果我希望shell命令的输出插入当前缓冲区的某个点,而保留缓冲区的其他内容不变,我应该为
output-buffer
传递一个非
nil
参数,为
REPLACE
传递
nil
参数

但是,如果我在
*scratch*
缓冲区中执行此代码(不是我正在处理的真实代码,而是演示此问题的最小案例):

缓冲区的全部内容被删除并替换为
wc
的输出


当以非交互方式使用时,区域上的
shell命令是否已损坏,或者我是否误读了文档?如果是后者,我如何更改上面的代码以在点插入
wc
的输出,而不是替换缓冲区的内容?理想情况下,我希望有一个通用的解决方案,它不仅可以在整个缓冲区上运行命令,如最小示例(即
(point min)
(point max)
),但对于以区域作为输入运行命令,然后在不删除区域的情况下在点插入结果的情况也是如此。

如果您按照函数源代码的链接进行操作,您将很快看到它确实:

(if (or replace
    (and output-buffer
     (not (or (bufferp output-buffer) (stringp output-buffer)))))
我不知道为什么会这样,tho。在任何情况下,这主要是指作为一个命令,而不是一个功能;在Elisp中,我建议您使用
调用流程区域

在我的例子中(emacs 24.3,不知道您使用的是什么版本),文档在可选参数中略有不同:

Optional fourth arg OUTPUT-BUFFER specifies where to put the
command's output.  If the value is a buffer or buffer name, put
the output there.  Any other value, including nil, means to
insert the output in the current buffer.  In either case, the
output is inserted after point (leaving mark after it).
检查是否删除输出(当前)缓冲区内容的代码如下:

(if (or replace
    (and output-buffer
     (not (or (bufferp output-buffer) (stringp output-buffer)))))
很明显,在您的例子中,它不是字符串或缓冲区,也不是nil,因此它将用输出替换当前缓冲区内容。但是,如果我尝试:

(shell-command-on-region
 (point-min) (point-max) "wc" nil nil)
然后不删除缓冲区,将输出放入“Shell命令输出”缓冲区。乍一看,我认为这个函数没有正确实现。即使文档的两个版本似乎也与代码不符。

您错了 在emacs lisp代码中,在区域上使用交互式命令(如
shell命令)
)不是一个好主意。改用

Emacs是错误的 区域
上的
shell命令中有一个错误:它没有将
replace
参数向下传递到
调用进程区域
;以下是修复方法:

=== modified file 'lisp/simple.el'
--- lisp/simple.el  2013-05-16 03:41:52 +0000
+++ lisp/simple.el  2013-05-23 18:44:16 +0000
@@ -2923,7 +2923,7 @@ interactively, this is t."
      (goto-char start)
      (and replace (push-mark (point) 'nomsg))
      (setq exit-status
-       (call-process-region start end shell-file-name t
+       (call-process-region start end shell-file-name replace
                     (if error-file
                     (list t error-file)
                       t)

我很快就会提交。

谢谢。我从文档中看到,
callprocessregion
在region
的功能上实现了一个超集的
shell命令,因此选择前者是有意义的。但是,如果在区域
上使用
shell命令“不是一个好主意”,那么为什么提供(并记录)它的非交互形式?可能存在这样一种情况:区域
上的
shell命令是合适的(例如,用于shell命令解析)-但仅当您知道
调用过程区域
不是时。@dodgethesteamroller:任何命令都会自动成为您可以从Elisp调用的函数。有些命令最好不要从Elisp调用。其中一些经常被误用,以至于字节编译器看到它时会发出警告。你是对的。抢手货我引用的文档来自Emacs 23.2.1,但我同意这两个版本都不符合实际的代码行为。只因为@sds在Emacs代码库中提交了实际更改,所以给@sds“correct”。Emacs 24.4将文档中的“include nil”替换为“include nil”,因为当OUTPUT-BUFFER为nil时,输出不会插入当前缓冲区,而是插入“Shell命令输出”。啊,太好了。这使文档与实现保持一致。作为一名Elisp新手,我有没有办法判断某个特定函数是否“主要是作为命令使用的”?在我看来,如果一个函数的非交互版本被记录下来,那么在非交互代码中使用它应该是公平的。还是有些微妙之处我不明白?不想刺耳,但真正好奇。@Dodge不打算从Lisp调用的TeamRoller函数通常都是这样记录的-例如,请参见前一行的DocString
或替换string
。否则,如果函数设置了标记、在回显区域显示消息或切换到其他缓冲区,则表明函数不打算从Lisp调用。从Lisp调用此类函数可能仍然有用,但仅在非常特定的情况下,例如在交互式函数周围创建一个简单的包装器时。
(shell-command-on-region
 (point-min) (point-max) "wc" nil nil)
=== modified file 'lisp/simple.el'
--- lisp/simple.el  2013-05-16 03:41:52 +0000
+++ lisp/simple.el  2013-05-23 18:44:16 +0000
@@ -2923,7 +2923,7 @@ interactively, this is t."
      (goto-char start)
      (and replace (push-mark (point) 'nomsg))
      (setq exit-status
-       (call-process-region start end shell-file-name t
+       (call-process-region start end shell-file-name replace
                     (if error-file
                     (list t error-file)
                       t)