简体   繁体   English

如何从Clojure内部运行交互式CLI程序?

[英]How to run an interactive CLI program from within Clojure?

I'd like to run an interactive CLI program from within Clojure (eg, vim) and be able to interact with it. 我想从Clojure(例如vim)中运行一个交互式CLI程序,并能够与其交互。

In bash and other programming languages, I can do that with 在bash和其他编程语言中,我可以使用

vim > `tty`

I tried to do the same in Clojure: 我试图在Clojure中做同样的事情:

(require '[clojure.java.shell :as shell])
(shell/sh "vim > `tty`")

but it just opens vim without giving me tty. 但是它只是打开vim而没有给我tty。


Background: I'm developing a Clojure CLI tool which parses emails and lets a user edit the parsed data before saving them on the disk. 背景:我正在开发一种Clojure CLI工具,该工具可以解析电子邮件,并允许用户编辑已解析的数据,然后再将其保存到磁盘上。 It works the following way: 它的工作方式如下:

  1. Read a file with email content and parse it. 读取包含电子邮件内容的文件并进行解析。 Each email is stored as a separate file. 每封电子邮件都存储为单独的文件。
  2. Show a user the parsed data and let the user edit the data in vim. 向用户显示已解析的数据,并让用户在vim中编辑数据。 Internally I create a temporary file with the parsed data, but I don't mind doing it another way if that would solve my issue. 在内部,我使用已解析的数据创建一个临时文件,但是如果可以解决我的问题,我不介意以其他方式进行操作。
  3. After a user finished editing the parsed data (they might decide to keep it as it is) append the data to a file on a disk. 用户完成对已解析数据的编辑(他们可能决定保留原样)后,将数据追加到磁盘上的文件中。 So all parsed data are saved to the same file. 因此,所有解析的数据都保存到同一文件中。
  4. Go to 1st step if there are any files with emails left. 如果还有电子邮件剩余的文件,请转到第一步。

This code relies on Clojure Java interop to make use of Java's ProcessBuilder class. 此代码依赖于Clojure Java互操作来利用Java的ProcessBuilder类。

(defn -main
[]
;use doseq instead of for because for is lazily evaluated
(doseq [i [1 2 3]]
;extract current directory from system variable
(let [file-name (str "test" i ".txt")
      working-directory (trim-newline (:out (sh "printenv" "PWD")))]
  (spit file-name "")

  ;this is where fun begins. We use ProcessBuilder to forward commands to terminal
  ;we pass a list of commands and their arguments to its constructor
  (let [process-builder (java.lang.ProcessBuilder. (list "vim" (str working-directory "/" file-name)))
  ;inherit is a configuration constant
        inherit (java.lang.ProcessBuilder$Redirect/INHERIT)]
  ;we configure input, output and error redirection
  (.redirectOutput process-builder inherit)
  (.redirectError process-builder inherit)
  (.redirectInput process-builder inherit)

  ;waitFor used to block execution until vim is closed
  (.waitFor (.start process-builder))
  )
  ;additional processing here
)
)
;not necessary but script tends to hang for around 30 seconds at end of its execution
;so this command is used to terminate it instantly
(System/exit 0)
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM