我发现使用 (use '[clojure.java.shell :only [sh]])
命令可以在 Clojure 中执行 shell 命令。虽然 (sh "ls" "-a")
命令可以正常工作,但是 (sh "ls" "-a" "| grep" "Doc")
命令就不行了。有什么技巧吗?
clojure.java.shell/sh
执行一个命令(作为sh
函数传递的第一个参数),并指定参数(作为传递给sh
的其余参数)。
当你执行:
(sh "ls" "-a" "| grep" "Doc")
你请求执行带有参数-a
、| grep
和Doc
的ls
。
当您在终端中键入ls -a | grep Doc
时,shell会将它解释为执行ls
,获取其标准输出,并将其作为标准输入传递给另一个进程(grep
),而该进程应该由shell启动。
你可以通过启动ls
作为一个进程,获取它的标准输出,然后执行grep
,并将来自ls
的输出作为它的输入来模拟shell正在执行的操作。
更简单的解决方案是,只需请求一个shell
进程来执行所有操作,就好像在终端中输入一样:
(sh "bash" "-c" "ls -a | grep Doc")
重要的是要将-c
和ls ...
作为单独的参数传递,以便bash将它们作为单独的参数获取。您还需要将要执行的整个命令作为一个字符串(ls -a | grep Doc
)。否则,只有在-c
之后的第一个参数将被视为命令。例如,下面的内容不能达到你的期望:
(sh "bash" "-c" "ls -a" "|" "grep Doc")
(":out (sh "ls" "-a"))
的输出到另一个(sh "grep" "Doc")
来完成它? - shakedzysh
的:in
选项来传递前一个进程的:out
值。但是,使用它会失去从一个进程流式传输数据的功能 - 你将缓冲一个进程的所有输出,当它完成时,你将把所有内容传递给另一个进程。Shell 使用管道,其中数据从一个进程流式传输到另一个进程,无需缓冲所有内容。你可以使用java.lang.Runtime.exec()
和java.lang.Process.getOutputStream
来获取第一个进程的输出数据并将其传递给下一个进程,但 Clojure 的sh
不支持它。 - Piotrek Bzdyl