【问题标题】:ProcessBuilder - No such file or directory (but Runtime.exec() works)ProcessBuilder - 没有这样的文件或目录(但 Runtime.exec() 有效)
【发布时间】:2016-01-05 03:27:24
【问题描述】:

为什么我在这两种情况下会遇到不同的行为?我错过了什么吗?

命令:

new ProcessBuilder().directory(
                    Paths.get(System.getProperty("user.dir")).toFile())
                    .command("/usr/bin/java -Djava.library.path=/Users/myusername/myproject/lib/DynamoDBLocal_lib/ -jar /Users/myusername/myproject/lib/DynamoDBLocal.jar  -sharedDb").start();

堆栈跟踪:

Exception in thread "main" java.lang.RuntimeException: java.io.IOException: Cannot run program "/usr/bin/java -Djava.library.path=/Users/myusername/myproject/lib/DynamoDBLocal_lib/ -jar /Users/myusername/myproject/lib/DynamoDBLocal.jar  -sharedDb" (in directory "/Users/myusername/myproject"): error=2, No such file or directory
    at com.comcast.tvx.app.xreserver.Main.exec(Main.java:47)
    at com.comcast.tvx.app.xreserver.Main.main(Main.java:16)
Caused by: java.io.IOException: Cannot run program "/usr/bin/java -Djava.library.path=/Users/myusername/myproject/lib/DynamoDBLocal_lib/ -jar /Users/myusername/myproject/lib/DynamoDBLocal.jar  -sharedDb" (in directory "/Users/myusername/myproject"): error=2, No such file or directory
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
    at com.comcast.tvx.app.xreserver.Main.exec(Main.java:44)
    ... 1 more
Caused by: java.io.IOException: error=2, No such file or directory
    at java.lang.UNIXProcess.forkAndExec(Native Method)
    at java.lang.UNIXProcess.<init>(UNIXProcess.java:248)
    at java.lang.ProcessImpl.start(ProcessImpl.java:134)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
    ... 2 more

失败案例的环境:

{PATH=/usr/bin:/bin:/usr/sbin:/sbin
JAVA_STARTED_ON_FIRST_THREAD_1074=1
SHELL=/bin/zsh
SECURITYSESSIONID=186a4
USER=myusername
JAVA_MAIN_CLASS_25188=com.comcast.tvx.app.xreserver.Main
APP_ICON_1074=../Resources/Eclipse.icns
COMMAND_MODE=unix2003
TMPDIR=/var/folders/t_/dlj2wfdj0bx2xl6mnnqmxyhj99pf4b/T/
SSH_AUTH_SOCK=/tmp/launch-Bhd1It/Listeners
DISPLAY=/tmp/launch-PuSx66/org.macosforge.xquartz:0
__CF_USER_TEXT_ENCODING=0x529B388B:0:0
Apple_PubSub_Socket_Render=/tmp/launch-hB7zpQ/Render
__CHECKFIX1436934=1
LOGNAME=myusername
HOME=/Users/myusername}

更多信息

当我使用 Runtime.exec() 执行此操作时,环境看起来相同,但我没有收到错误:

命令:

Runtime.getRuntime().exec("/usr/bin/java -Djava.library.path=/Users/myusername/myproject/lib/DynamoDBLocal_lib/ -jar /Users/myusername/myproject/lib/DynamoDBLocal.jar  -sharedDb")

后续案例环境:

{PATH=/usr/bin:/bin:/usr/sbin:/sbin
JAVA_STARTED_ON_FIRST_THREAD_1074=1
SHELL=/bin/zsh
JAVA_MAIN_CLASS_25360=com.comcast.tvx.app.xreserver.Main
SECURITYSESSIONID=186a4
USER=myusername
APP_ICON_1074=../Resources/Eclipse.icns
COMMAND_MODE=unix2003
TMPDIR=/var/folders/t_/dlj2wfdj0bx2xl6mnnqmxyhj99pf4b/T/
SSH_AUTH_SOCK=/tmp/launch-Bhd1It/Listeners
DISPLAY=/tmp/launch-PuSx66/org.macosforge.xquartz:0
__CF_USER_TEXT_ENCODING=0x529B388B:0:0
Apple_PubSub_Socket_Render=/tmp/launch-hB7zpQ/Render
__CHECKFIX1436934=1
LOGNAME=myusername
HOME=/Users/myusername}

【问题讨论】:

    标签: java


    【解决方案1】:

    尝试改变这一行:

    .command("/usr/bin/java -Djava.library.path=/Users/myusername/myproject/lib/DynamoDBLocal_lib/ -jar /Users/myusername/myproject/lib/DynamoDBLocal.jar  -sharedDb").start();
    

    to(一直向右滚动查看差异):

    .command("/usr/bin/java -Djava.library.path=/Users/myusername/myproject/lib/DynamoDBLocal_lib/ -jar /Users/myusername/myproject/lib/DynamoDBLocal.jar  -sharedDb".split("\\s+")).start();
    

    解释:command() 的输入应该是一个字符串数组(或列表),每个字符串都是另一个参数(或“令牌”)。它不应包含空格!

    来自docs

    命令,表示外部程序文件的字符串列表 被调用及其参数,如果有的话。哪些字符串列表代表 有效的操作系统命令取决于系统。例如,它 每个概念参数都是此列表中的一个元素,这是很常见的, 但是有些操作系统需要程序 自己标记命令行字符串 - 在这样的系统上,Java 实现可能需要命令恰好包含两个元素。

    【讨论】:

    • 如果有人想知道为什么要这样设计,包括我珍贵的自己,它可以让您不必担心转义特殊字符。可悲的是,当您查看签名而不是 javadoc 时,您认为这意味着其他东西。
    猜你喜欢
    • 1970-01-01
    • 2013-02-17
    • 2021-06-24
    • 1970-01-01
    • 1970-01-01
    • 2015-02-20
    • 2023-03-22
    相关资源
    最近更新 更多