Emacs 等待shell命令完成,然后再执行另一个elisp命令

Emacs 等待shell命令完成,然后再执行另一个elisp命令,emacs,elisp,Emacs,Elisp,我正在努力做到以下几点: 在emacs中打开shell,并将其放入项目文件夹中 从存储库执行mercurial pull “等待”直到拉动完成 向elisp命令传达拉动已完成,elisp命令首先启动shell命令,以便它可以继续使用compile命令来构建树 在从.emacs文件内部启动新的elisp命令之前,是否有一种方法/代码可以让我知道shell命令何时完成?我认为您不必启动物理shell来完成此操作。在您的elisp中,您可以使用例如调用processshell命令,它将等待您输入的命令

我正在努力做到以下几点:

  • 在emacs中打开shell,并将其放入项目文件夹中
  • 从存储库执行mercurial pull
  • “等待”直到拉动完成
  • 向elisp命令传达拉动已完成,elisp命令首先启动shell命令,以便它可以继续使用compile命令来构建树

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

    我认为您不必启动物理shell来完成此操作。在您的elisp中,您可以使用例如
    调用processshell命令
    ,它将等待您输入的命令,例如
    “cd directory;hg pull”
    完成

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

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

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

    @Francesco先前在以下链接中回答了类似的问题:

    我发现使用
    start process
    作为let绑定变量会导致它立即运行,而不是等待函数中更理想的时刻。我还发现,
    set process sentinel
    阻止使用先前定义的let绑定变量。与使用let绑定变量或全局变量不同,另一种选择是使用缓冲区局部变量——例如,
    (defvar my local variable nil“This is my local variable.”)(使变量buffer local“my local variable”)
    ——并在函数中设置它——例如,
    (setq my local variable“hello world”)
    。虽然我看到的大多数示例都考虑了sentinel,但我喜欢将所有内容都包含在一个函数中——例如,下面的代码片段演示了:

    (设置进程哨兵)
    (启动流程)
    “我的进程名称一”
    “*输出缓冲区*”
    “/path/to/executable”
    “论点一”
    “论点二”
    “论点三”)
    (λ(pe)(当(=0(过程退出状态p))时)
    (设置进程哨兵)
    (启动流程)
    “我的进程名称2”
    nil;;不使用输出缓冲区的示例
    “/path/to/executable”
    “论点一”
    “论点二”
    “论点三”)
    (λ(pe)(当(=0(过程退出状态p))时)
    (设置进程哨兵)
    (启动流程…)(()()()()()))
    
    感谢Diego的回复。我想在emacs中启动一个shell,这样我就可以看到拉动的进度。有时会出现合并并发症,需要采取进一步行动。因此,shell命令将处理拉伸。我需要一种方法来等待它完成,这样我就可以使用compile命令来启动make进程。我也可以从shell内部使用make本身,但我喜欢编译包提供的功能,如果它在编译过程中显示错误,并可以选择直接跳转到错误。Diego,是否至少有一种方法可以主动将进程调用的输出转发到emacs缓冲区?是的,只需阅读
    启动流程的文档
    。使用它启动一个进程,将输出定向到某个缓冲区,启动后,使用
    display buffer
    显示输出<代码>启动流程将返回流程对象。使用
    Set process sentinal
    (读取sentinal的文档)设置流程的sentinal函数。当流程成功完成时,使用sentinal执行elisp。正如泰勒在上面所说,您可以启动流程并“断开”输入,使用
    启动进程
    启动进程shell命令
    的任何变体,或者使用任何shell缓冲区并丢失有关进程何时完成的信息(尽管您可以像在shell缓冲区中一样控制合并错误)。我想到的另一件事是,你可以启动这个反复无常的过程,这样当它发现冲突时就会失败。通过这种方式,您可以了解错误并自行处理冲突。由于冲突往往很少,这将在90%的时间内起作用,并且不需要任何操作。一旦Emacs启动了一个异步进程,就真的无法判断它何时完成。更复杂的是,如果您打开一个交互式shell,当
    hg pull
    完成时,该过程实际上并没有完成,它仍然是活动的!在这种情况下,大多数项目将只使用两个命令—一个用于步骤1和2,另一个用于步骤4。ESS()在类似的上下文中也能做到这一点。这就是我所使用的--
    启动进程
    设置进程哨兵
    :这个例子适用于latexmk,但它也适用于其他东西。感谢Lawlist,这很有效!lawlist,我无法理解我的局部变量背后的目的。您是否可以将其包含在上面的示例中以了解其效果?如果存在太多全局变量,且这些变量具有值和通用名称,则某些函数可能会失败,如果它们碰巧使用相同的变量,例如,
    文件名
    文件名
    。通过将变量定义为buffer local,它在任何地方都是
    nil
    ,除了正在使用它的一个缓冲区,并且一旦缓冲区关闭,它就会消失。我更喜欢使用let-bound变量,但在
    set-process-sentinel
    中,这不太管用。因此,最好的选择似乎是使用缓冲区局部变量来缩短脚本编写时间,而不是重复相同的长值。下面是一个链接,指向一个更新的示例,该示例使用缓冲区局部变量而不是全局或let绑定变量来缩短脚本编写时间:下面是另一个示例:只是为了澄清,您仍然需要适当地命名变量(以避免与其他变量发生潜在的名称冲突),而不管您是否只分配缓冲区本地值
    (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))))))))