2012-04-06 28 views
4

假設我有一個目錄A和子目錄B.我將CD cd到A並啓動lisp。在這個lisp過程中,我想啓動一個Python子進程,Python將B視爲其當前工作目錄。 lisp進程需要在A中有cwd,而python進程應該在b中有cwd。我如何以跨平臺,簡單的方式做到這一點?Common Lisp:啓動具有不同工作目錄的子進程而不是lisp進程

我在尋找與CCL和SBCL(可能使用「運行程序功能)的作品,以及適用於Windows,Linux和OS X的解決方案

我看着CCL運行程序文檔,我沒有看到改變啓動過程的順序的方法。

我看着Python命令行參數,並沒有看到會改變python進程的cwd的參數。

我想到了一個運行程序調用'cd B;蟒蛇......「,但我不確定這是如何工作的,因爲它確實運行了兩個程序;裁談會,然後python。

Python代碼被作爲輸入提供(作爲一個文件),所以我不能改變任何代碼(通過添加os.chdir()調用或類似的)。

將python輸入文件作爲子進程啓動的python包裝文件並不理想,因爲我正在發送stdin並監聽由lisp啓動的python進程的stdout。在lisp和傳遞輸入文件的python進程之間添加另一個子進程意味着我需要做很多stout/stdin中繼,並且我感覺這會變得很脆弱。

krzysz00的方法工作得很好。由於目錄更改是在lisp中處理的,所以在啓動python進程之前,這種方法將用於啓動不同子目錄中的其他進程(而不僅僅是python)。

有關文檔,這裏是我的代碼,使用krzsz00的方法,適用於SBCL & CCL。請注意,它使用Hoyte的defmacro!宏觀,從Let Over Lambda,輕鬆避免不必要的變量捕獲:

#+:SBCL 
(defun cwd (dir) 
    (sb-posix:chdir dir)) 

(defun getcwd() 
    #+SBCL (sb-unix:posix-getcwd) 
    #+CCL (current-directory)) 

(defmacro! with-cwd (dir &body body) 
    `(let ((,g!cwd (getcwd))) 
    (unwind-protect (progn 
         (cwd ,dir) 
         ,@body) 
    (cwd ,g!cwd)))) 

用法:

(with-cwd "./B" 
    (run-program ...)) 

回答

6

要(可移植喜歡你的Python程序)運行外部程序見external-program。要更改當前的工作目錄,請使用以下重現的文件http://files.b9.com/lboot/utils.lisp中稍微修改的(公共域)功能cwd

(defun cwd (&optional dir) 
    "Change directory and set default pathname" 
    (cond 
    ((not (null dir)) 
    (when (and (typep dir 'logical-pathname) 
      (translate-logical-pathname dir)) 
     (setq dir (translate-logical-pathname dir))) 
    (when (stringp dir) 
     (setq dir (parse-namestring dir))) 
    #+allegro (excl:chdir dir) 
    #+clisp (#+lisp=cl ext:cd #-lisp=cl lisp:cd dir) 
    #+(or cmu scl) (setf (ext:default-directory) dir) 
    #+cormanlisp (ccl:set-current-directory dir) 
    #+(and mcl (not openmcl)) (ccl:set-mac-default-directory dir) 
    #+openmcl (ccl:cwd dir) 
    #+gcl (si:chdir dir) 
    #+lispworks (hcl:change-directory dir) 
    #+sbcl (sb-posix:chdir dir) 
    (setq cl:*default-pathname-defaults* dir)) 
    (t 
    (let ((dir 
     #+allegro (excl:current-directory) 
     #+clisp (#+lisp=cl ext:default-directory #-lisp=cl lisp:default-directory) 
     #+(or cmu scl) (ext:default-directory) 
     #+sbcl (sb-unix:posix-getcwd/) 
     #+cormanlisp (ccl:get-current-directory) 
     #+lispworks (hcl:get-working-directory) 
     #+mcl (ccl:mac-default-directory) 
     #-(or allegro clisp cmu scl cormanlisp mcl sbcl lispworks) (truename "."))) 
     (when (stringp dir) 
    (setq dir (parse-namestring dir))) 
     dir)))) 

結合這兩個功能,你想要的代碼是:

(cwd #p"../b/") 
(external-program:start "python" '("file.py") :output *pythins-stdout-stream* :input *pythons-stdin-stream*) 
(cwd #p"../a/") 

這將cd到B,運行Python進程彷彿python file.py &,發送蟒蛇進程的標準輸入/輸出到指定的(詳情請查看external-program文檔),最後執行另一個cwd,將lisp進程返回給A.如果lisp進程應等到python進程完成,請使用external-program:run而不是external-program:start

+0

好的建議;謝謝;我沒有使用外部程序兼容層b/c我只需要它用於sbcl和ccl,那些運行程序基本相同,並且我不能輕易地爲這個代碼加載軟件包,b/c它是沒有被用於服務器端。 – 2012-04-07 19:23:17

+0

這裏對於多線程程序是否有任何影響,或者是在每個線程的基礎上改變了「cwd」? – Inaimathi 2014-01-07 20:25:35

+0

我認爲'cwd'是我的'thread_safety(5)'快速瀏覽的每個線程,但我並不完全確定。看看它是否有效。 – krzysz00 2014-01-08 16:31:49

0

我不知道是什麼口齒不清,但能工作的呢?

import subprocess 
    subprocess.Popen('python myscript.py', cwd='B') 

http://docs.python.org/library/subprocess.html

+0

我添加了一個額外的約束。在lisp和最終的python進程之間插入一個python包裝進程並不理想;但也許我可以啓動一個加載python包裝文件的python進程;該文件將cd,然後加載python輸入文件? – 2012-04-06 22:29:47

+0

我不得不說,這是一個非常尷尬的問題。 http://cybertiggyr.com/gene/pathnames-0/node11.html – apple16 2012-04-06 22:49:33

+0

@Epic_orange:謝天謝地別人寫的可移植性層。 – krzysz00 2012-04-07 01:48:36

1

我最終把krzysz00的建議寫入了一個可以找到的包here

然後有人指出,UIOP自帶getcwdchdir。如果你有一個相當新的lisp,UIOP應該包含在你的版本asdf中。