我有一个简单的Python文件hello.py
,其中包含内容:print("Hello World")
,当我尝试使用(sh "python3 hello.py")
从REPL运行它时,我会得到
Execution error (IOException) at java.lang.UNIXProcess/forkAndExec (UNIXProcess.java:-2).
error=2, No such file or directory
显然,当我在shell中运行python3 hello.py
时,程序就会运行。如何从Clojure repl运行Python文件?
将每个execve()
元素(也就是说,在实际启动新进程时传递给操作系统的字符串数组中的每个元素(作为一个单独的参数:
(use '[clojure.java.shell :only [sh]])
(sh "python3" "hello.py")
与其名称可能暗示的相反,clojure.java.shell/sh
实际上并没有调用sh
。相反,它直接调用Runtime.exec()
,后者接受一个直接的参数列表。
如果想要调用shell,可以显式地执行:
(use '[clojure.java.shell :only [sh]])
(sh "sh" "-c" "python3 hello.py")
或者,更好的做法是,使hello.py
成为具有有效shebang的可执行文件,并直接调用它。也就是说,确保hello.py
以#!/usr/bin/env python3
开始,运行chmod +x ./hello.py
,并运行use:
(use '[clojure.java.shell :only [sh]])
(sh "./hello.py")
(此外,请考虑放弃.py
扩展;就像您运行pip
而不是pip.py
,运行ls
而不是ls.elf
一样,可执行脚本也不应该有扩展(。
您可能对这个用于运行shell命令的辅助函数感兴趣
(shell-cmd <cmd-str>)
在默认操作系统shell(/bin/bash(中运行命令字符串;退货生成Clojure映射。示例:
(shell-cmd "ls -ldF *")
结果:
{:exit 0 ; unix exit status (0 -> normal)
:err '' ; text from any errors
:out '...' ; text output as would printed to console
}
首先尝试使用unix命令来帮助诊断任何PATH问题。
更新
查尔斯的回答是对的。当您通过shell/sh
调用时,每个参数都需要一个不同的字符串。示例:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require
[tupelo.misc :as misc]
[clojure.java.shell :as shell] ))
(dotest
; `tupelo.misc/shell-cmd` calls bash first, so space is OK
(is= (misc/shell-cmd "python3 hello.py")
{:exit 0, :out "Hello Worldn", :err ""})
; calls `python3` directly. Need separate string "hello.py"
(is= (shell/sh "python3" "hello.py")
{:exit 0, :out "Hello Worldn", :err ""})
; fails since looking for a single command "python3 hello.py"
(throws? (shell/sh "python3 hello.py")))