2012-04-06 14 views
4

Angenommen, ich habe ein Verzeichnis A und Unterverzeichnis B. Ich cd in A und starten Lisp. In diesem Lisp-Prozess möchte ich einen Python-Subprozess starten, in dem Python B als sein aktuelles Arbeitsverzeichnis sieht. Der Lisp-Prozess muss in A cwd haben, und der Python-Prozess sollte cwd in B haben. Wie mache ich das auf plattformübergreifende, einfache Weise?Common Lisp: Starten Sie Subprozess mit anderen Arbeitsverzeichnis als Lisp Prozess

Ich bin für eine Lösung, die mit CCL und SBCL arbeitet (wahrscheinlich mit ‚run-Programm-Funktion), und arbeitet für Windows, Linux und OS X.

schaute ich auf dem CCL-Laufprogramm Dokumentation, und ich sah keine Möglichkeit, die cwd des gestarteten Prozesses zu ändern.

Ich sah Python-Befehlszeilenargumente, und ich sah keine, die die cwd des Python-Prozesses ändern würde.

Ich dachte über einen Programmaufruf für 'CD B; Python ... ', aber ich bin nicht sicher, wie das funktionieren würde, da es wirklich zwei Programme ausführt; CD und dann Python.

Der Python-Code wird als Eingabe bereitgestellt (als Datei), daher kann ich diesen Code nicht ändern (indem ich einen Aufruf von os.chdir() oder ähnliches hinzufüge).

Eine Python-Wrapper-Datei, die die Python-Eingabedatei als Subprozess startet, ist nicht ideal, weil ich stdin sende und den stdout des python-Prozesses abhöre, der von lisp gestartet wird. Das Hinzufügen eines anderen Unterprozesses zwischen lisp und dem Python-Prozess, der die Eingabedatei verfälscht, bedeutet, dass ich eine Menge Stout/Stdin-Relaying durchführen müsste, und ich habe das Gefühl, dass dies spröde wäre.

Krzysz00 Ansatz arbeitete sehr gut. Da die Verzeichnisänderung in Lisp behandelt wird, bevor der Python-Prozess gestartet wird, funktioniert dieser Ansatz zum Starten anderer Prozesse in verschiedenen Unterverzeichnissen (nicht nur Python).

Für die Dokumentation, hier ist mein Code mit krzsz00 Ansatz, der für SBCL & CCL funktioniert. Beachten Sie, dass es Hoyte Defmacro verwendet! Makro, von Let Over Lambda, vermeiden leicht unerwünschten Variable Capture:

#+: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)))) 

Verbrauch:

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

Antwort

6

externe Programme auszuführen (wie Ihr Python-Prozess portably) sehen external-program. Um das aktuelle Arbeitsverzeichnis zu ändern, verwenden Sie diese leicht modifizierte (Public Domain) Funktion cwd aus der Datei http://files.b9.com/lboot/utils.lisp, die unten wiedergegeben wird.

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

Die Kombination dieser beiden Funktionen, die Code Sie wollen, ist:

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

Dies wird cd nach B, die Python-Prozess ausgeführt, als ob durch python file.py &, die Python-Prozess stdin/stdout an die angegebene senden Streams (siehe die external-program Dokumentation für weitere Details), und führen Sie schließlich einen weiteren cwd aus, der den Lisp-Prozess an A zurückgibt.Wenn der Lisp-Prozess warten soll, bis der Python-Prozess beendet ist, verwenden Sie external-program:run anstelle von external-program:start.

+0

Nette Vorschläge; Vielen Dank; Ich habe den externen Programmkompatibilitäts-Layer b/c nicht benutzt. Ich brauche ihn nur für sbcl und ccl, das Run-Programm für diese ist im Grunde identisch, und ich kann nicht einfach Pakete für diesen Code laden, b/c ist es Server-Seite nicht verwendet. –

+0

Gibt es hier irgendwelche Auswirkungen auf Multithread-Programme oder wird 'cwd' pro Thread geändert? – Inaimathi

+0

Ich denke 'cwd' ist per-Thread von meinem schnellen Skim von' thread_safety (5) ', aber ich bin mir nicht ganz sicher. Sehen Sie, ob es funktioniert. – krzysz00

0

Ich weiß nicht, was Lisp konnte aber diese Arbeit?

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

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

+0

Ich fügte eine zusätzliche Einschränkung hinzu. Das Einfügen eines Python-Wrapper-Prozesses zwischen dem Lisp- und dem endgültigen Python-Prozess ist nicht ideal. aber vielleicht könnte ich einen Python-Prozess starten, der eine Python-Wrapper-Datei lädt; diese Datei wird cd, dann laden Sie die Python-Eingabedatei? –

+0

Ich muss sagen, das ist ein sehr peinliches Problem. http://cybertiggyr.com/gene/pathnames-0/node11.html – apple16

+0

@Epic_orange: Gott sei Dank hat jemand die Tragbarkeitsschicht geschrieben. – krzysz00

1

Ich schrieb krzysz00's Vorschlag in ein Paket, das here gefunden werden kann.

Dann wies jemand darauf hin, dass UIOP mit getcwd und chdir kommt. Wenn Sie ein ziemlich neues Lispeln haben, sollte UIOP in Ihrer Ausgabe von asdf enthalten sein.