如何在elisp中使用filter执行sudo命令

时间:2013-05-17 15:15:26

标签: emacs lisp elisp

我想使用elisp执行特权命令,然后在看到某些输出时使用过滤器进行进一步处理。

我的理解是,在详尽的RTFM之后,我可以:

  1. default-directory设置为以“/ sudo :: /”开头的路径。
  2. 致电start-file-process以启动将在sudo下运行的流程。
  3. 这是我写的一个尝试这样做的函数:

    (defun start-vpn (config-file password-file callback)
      "Starts the VPN connection, waits for a DHCP address,
    then invokes callback with the address it got."
      (let* ((default-directory "/sudo::/tmp")
             (buff (get-buffer-create "*openvpn*"))
             (proc (start-file-process "openvpn" "*openvpn*"
                                       "/usr/local/sbin/openvpn"
                                       (concat "--config " config-file)
                                       (concat "--auth-user-pass " password-file))))
        (set-process-filter proc
                            (lambda (proc output)
                              (message "Got output: " output)
                              (let ((ip (get-vpn-ip-address output)))
                                (when ip
                                  (callback ip)))))))
    

    当我运行它时,我在*Messages*缓冲区中看到以下输出:

    start-vpn
    Tramp: Opening connection for root@localhost using sudo...
    Tramp: Sending command `exec sudo -u root -s -H -p Password:'
    
    Tramp: Waiting for prompts from remote shell
    Tramp: Sending command `exec sudo -u root -s -H -p Password:'
    Tramp: Found remote shell prompt on `localhost'
    Tramp: Opening connection for root@localhost using sudo...done
    (lambda (proc output) (message "Got output: " output) (let ((ip ...)) (if ip (progn ...))))
    Got output: 
    

    ...并且函数创建的*openvpn*缓冲区中没有输出。

    我不是elisp的专家,所以我怀疑我犯的是一些愚蠢的错误。我对"(lambda (proc ..."缓冲区中的*Messages*非常好奇。

    任何建议,批评或提示都表示赞赏。谢谢!

1 个答案:

答案 0 :(得分:3)

首先,在消息缓冲区中看到(lambda ...的原因是set-process-filter返回过滤器函数,因此start-vpn也会这样做。

您的message调用需要包含实际显示输出的格式说明符:

(message "Got output: %s" output)

并且(callback ip)不会有两个原因:

  • Emacs Lisp具有单独的函数和变量名称空间,因此(callback ip)将调用函数 callback(不存在),而您需要{{1}调用存储在变量 (funcall callback ip)中的函数。
  • 一旦你过去了,因为默认情况下Emacs Lisp使用动态范围,当你的lambda函数被调用时,callback的绑定已经消失。

    在Emacs 24中,您可以将callback设置为lexical-binding,上面的代码应该有效。无论如何,您可以明确使用t宏:

    lexical-let

    此宏使用黑魔术来保留lambda函数中(lexical-let ((callback callback)) (lambda (proc output) (message "Got output: " output) (let ((ip (get-vpn-ip-address output))) (when ip (funcall callback ip)))) 的值。