【问题标题】:Emacs - noninteractive call to shell-command-on-region always deletes region?Emacs - 对 shell-command-on-region 的非交互式调用总是删除区域?
【发布时间】:2013-05-23 17:40:11
【问题描述】:

函数 shell-command-on-region 的 Emacs 帮助页面显示(空格省略):

(shell-command-on-region START END COMMAND &optional OUTPUT-BUFFER
REPLACE ERROR-BUFFER DISPLAY-ERROR-BUFFER)

...
The noninteractive arguments are START, END, COMMAND,
OUTPUT-BUFFER, REPLACE, ERROR-BUFFER, and DISPLAY-ERROR-BUFFER.
...

If the optional fourth argument OUTPUT-BUFFER is non-nil,
that says to put the output in some other buffer.
If OUTPUT-BUFFER is a buffer or buffer name, put the output there.
If OUTPUT-BUFFER is not a buffer and not nil,
insert output in the current buffer.
In either case, the output is inserted after point (leaving mark after it).

If REPLACE, the optional fifth argument, is non-nil, that means insert
the output in place of text from START to END, putting point and mark
around it.

这不是最清楚的,但刚刚引用的最后几句话似乎是说,如果我希望将 shell 命令的输出插入到当前缓冲区中,而缓冲区的其他内容保持不变,我应该为OUTPUT-BUFFERnilREPLACE 传递一个非nil 参数。

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

(shell-command-on-region
 (point-min) (point-max) "wc" t nil)

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

shell-command-on-region 在非交互式使用时是否损坏,还是我误读了文档?如果是后者,我如何更改上面的代码以插入 wc 的输出而不是替换缓冲区的内容?理想情况下,我想要一个通用的解决方案,它不仅可以像最小示例那样在整个缓冲区上运行命令(即(point-min)(point-max)),而且还可以用于运行带有区域的命令的情况输入,然后将结果插入点而不删除区域。

【问题讨论】:

    标签: emacs elisp


    【解决方案1】:

    你错了

    在 emacs lisp 代码中使用像 shell-command-on-region 这样的交互式命令不是一个好主意。请改用call-process-region

    Emacs 错了

    shell-command-on-region 中有一个错误:它没有将replace 参数传递给call-process-region;这是修复:

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

    我会尽快提交。

    【讨论】:

    • 谢谢。我从文档中看到call-process-region 实现了shell-command-on-region 功能的超集,因此更喜欢前者是有意义的。但是,如果使用 shell-command-on-region 不是“一个好主意”,那为什么要提供(并记录)它的非交互式形式?
    • 在某些情况下shell-command-on-region 是合适的(例如,用于shell 命令解析) - 但前提是您知道call-process-region 不合适。
    • @dodgethesteamroller:任何命令都会自动成为您可以从 Elisp 调用的函数。有一些命令最好不要从 Elisp 调用。其中一些经常被滥用,以至于字节编译器在看到它时会发出警告。
    【解决方案2】:

    如果您点击函数源代码的链接,您会很快看到它确实如此:

    (if (or replace
        (and output-buffer
         (not (or (bufferp output-buffer) (stringp output-buffer)))))
    

    我不知道为什么会这样。无论如何,这主要是作为命令而不是函数。来自 Elisp,我建议您改用 call-process-region

    【讨论】:

    • 作为 Elisp 新手,有没有一种方法可以判断某个特定功能是否“主要作为命令”?在我看来,如果记录了函数的非交互式版本,那么在非交互式代码中使用它应该是公平的游戏。或者这里有一些我没有得到的微妙之处?不是刻薄,而是真正好奇。
    • @dodgethesteamroller 不打算从 Lisp 调用的函数通常是这样记录的——例如,参见 previous-linereplace-string 的文档字符串。否则,一个函数不打算从 Lisp 调用的一个很好的指示是它是否设置了标记,在回显区域中显示一条消息,或者切换到不同的缓冲区。从 Lisp 调用此类函数可能仍然有用,但仅在非常特殊的情况下,例如在交互式函数周围创建一个简单的包装器时。
    【解决方案3】:

    在我的情况下(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)))))
    

    因此,很明显将t 与您的情况一样,它不是字符串或缓冲区,也不是零,因此它将用输出替换当前缓冲区内容。但是,如果我尝试:

    (shell-command-on-region
     (point-min) (point-max) "wc" nil nil)
    

    那么缓冲区不会被删除,输出会被放入“Shell Command Output”缓冲区。乍一看,我会说该功能没有正确实现。就连这两个版本的文档似乎都与代码不符。

    【讨论】:

    • 你是对的。接得好。我引用的文档来自 Emacs 23.2.1,但我同意这两个版本都不符合实际的代码行为。仅因为 @sds 在 Emacs 代码库中提交了实际更改,才给他“正确”。
    • 并且 emacs 24.4 将文档中的“包括 nil”替换为“不包括 nil”,因为当 OUTPUT-BUFFER 为 nil 时,输出不会插入当前缓冲区,而是插入“Shell命令输出".
    • 啊,完美。这使文档与实现保持一致。
    猜你喜欢
    • 2010-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-16
    • 2016-02-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多