【问题标题】:Wait on shell command to finish before executing another elisp command在执行另一个 elisp 命令之前等待 shell 命令完成
【发布时间】:2014-04-11 20:19:33
【问题描述】:

我正在尝试执行以下操作:

  1. 在 emacs 中打开一个 shell 并 cd 进入项目文件夹
  2. 从存储库执行 mercurial pull。
  3. “等待”直到拉取完成
  4. 向 elisp 命令传达拉取已完成的信息,该命令启动 shell 命令开始,以便它可以继续使用编译命令来构建树。

在从 .emacs 文件中启动新的 elisp 命令之前,有没有一种方法/代码可以让我知道 shell 命令何时完成?

【问题讨论】:

  • 一旦 Emacs 启动了一个异步进程,真的没有办法知道它什么时候结束。更复杂的是,如果您正在打开一个交互式 shell,当 hg pull 完成时,该过程实际上并没有完成,它仍然存在!在这种情况下,大多数项目将只使用两个命令 - 一个用于第 1 步和第 2 步,另一个用于第 4 步。ESS (ess.r-project.org) 在类似的上下文中正是这样做的。
  • 这是我使用的 -- start-processset-process-sentinel: stackoverflow.com/a/18707182/2112489 该示例适用于 latexmk,但它也适用于其他东西。
  • 感谢 Lawlist,成功了!

标签: emacs elisp


【解决方案1】:

我认为您不必启动物理外壳即可。在您的 elisp 中,您可以使用例如 call-process-shell-command,它会等到您输入的命令(例如 "cd directory ; hg pull")完成。

要进行测试,您可以在*scratch* 窗口中尝试 (C-x C-e):

(call-process-shell-command "cd directory ; ls" nil t)

它会显示光标前那个目录的文件列表,它会等待执行下一个命令,直到命令完成。

【讨论】:

  • 感谢迭戈的回复。我想在 emacs 中启动一个 shell,这样我就可以看到 pull 的进度。有时会出现需要进一步操作的合并并发症。因此,shell 命令将处理拉动。我需要一种方法来等待它完成,这样我就可以使用编译命令来启动 make 过程。我也可以从 shell 内部使用 make 本身,但我喜欢 compile 包提供的功能,它在编译期间显示错误,并可选择直接跳转到错误。
  • Diego,至少有一种方法可以将进程调用的输出主动转发到 emacs 缓冲区中吗?
  • 是的,只需阅读start-process 的文档即可。使用它来启动一个输出定向到某个缓冲区的进程,在它启动后,使用display-buffer 显示输出。 start-process 将返回进程对象。使用set-process-sentinal 设置进程的哨兵功能(阅读哨兵的文档)当进程成功完成时使用哨兵执行elisp。
  • 作为上面的 Tyler cmets,您可以使用start-processstart-process-shell-command 的任何变体启动进程并“断开”输入,或者您使用任何shell 缓冲区并丢失有关何时进程已完成(尽管您可以在 shell 缓冲区中控制合并错误)。我想到的另一件事是,您可以启动 Mercurial 进程,以便在发现冲突时失败。这样您就可以被告知错误并自己处理冲突。由于冲突往往很少,这将在 90% 的时间内有效,并且不需要任何操作
【解决方案2】:

@Francesco 之前在以下链接回答了类似的问题:https://stackoverflow.com/a/18707182/2112489

我发现使用start-process 作为 let-bound 变量会导致它立即运行,而不是等到函数中更理想的时刻。我还发现set-process-sentinel 阻止使用之前定义的 let-bound 变量。除了使用 let-bound 变量或全局变量之外,另一种选择是使用缓冲区局部变量——例如,(defvar my-local-variable nil "This is my local variable.") (make-variable-buffer-local 'my-local-variable)——并将其设置在函数中——例如,(setq my-local-variable "hello-world")。尽管我看到的大多数示例都排除了哨兵,但我喜欢将所有内容都包含在一个函数中——例如,如下 sn-p 演示:

(set-process-sentinel 
  (start-process
    "my-process-name-one"
     "*OUTPUT-BUFFER*"
    "/path/to/executable"
    "argument-one"
    "argument-two"
    "argument-three")
  (lambda (p e) (when (= 0 (process-exit-status p))
    (set-process-sentinel 
      (start-process
        "my-process-name-two"
        nil ;; example of not using an output buffer
        "/path/to/executable"
        "argument-one"
        "argument-two"
        "argument-three")
      (lambda (p e) (when (= 0 (process-exit-status p))
        (set-process-sentinel 
          (start-process . . . ))))))))

【讨论】:

  • 法律列表,我无法弄清楚 my-local-variable 背后的目的。您能否将其包含在上面的示例中以了解效果?
  • 当存在太多具有变量值和通用名称的全局变量时,如果偶然使用相同的变量,某些函数可能会失败——例如,filenamefile-name。通过将变量定义为本地缓冲区,它在任何地方都是nil,除了正在使用它的那个缓冲区,并且一旦缓冲区关闭,它就会消失。我更喜欢使用 let-bound 变量,但这在set-process-sentinel 中效果不佳。所以最好的选择似乎是使用缓冲区局部变量来缩短脚本编写时间,而不是重复相同的长值。
  • 这是一个更新示例的链接,该示例使用缓冲区局部变量而不是全局变量或 let-bound 变量来缩短脚本编写:stackoverflow.com/q/18705774/2112489,这是另一个示例:stackoverflow.com/q/23039562/2112489
  • 澄清一下,您仍然需要适当地命名您的变量(以避免与其他变量的潜在名称冲突),无论您是否仅分配缓冲区局部值给他们。
  • lexical-let 是另一种选择
【解决方案3】:
(defun async-proc-with-context ()
  "experiment! set process completion context using the plist"
  (let* ((cmd "ls -la")
         (ctx "it finished")
         (output-buffer (generate-new-buffer (format "*bufname*")))
         (proc (progn
                 (async-shell-command cmd output-buffer)
                 (get-buffer-process output-buffer))))
    (if (process-live-p proc)
        (progn
          (process-put proc 'jw-ctx ctx) ;; set the context
          (set-process-sentinel proc '(lambda (process signal)
                                        (when (memq (process-status process) '(exit signal))
                                          (message (process-get process 'jw-ctx)) ;; get the context
                                          (shell-command-sentinel process signal))))))))

【讨论】:

    猜你喜欢
    • 2023-03-06
    • 2019-12-31
    • 1970-01-01
    • 2018-04-03
    • 2011-09-20
    • 2018-07-17
    • 2019-07-16
    • 2013-04-03
    • 1970-01-01
    相关资源
    最近更新 更多