I am trying to find out whether a command exists (eg. date
) using the command
shell builtin, on Ubuntu. However the following (scroll further below for java snippet)
//main.kt
fun main(){
val proc=ProcessBuilder("command","-v","date").start() //line 37
}
fails to run with stack trace
Exception in thread "main" java.io.IOException: Cannot run program "command": error=2, No such file or directory
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1143)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1073)
at MainKt.main(main.kt:37)
at MainKt.main(main.kt)
Caused by: java.io.IOException: error=2, No such file or directory
at java.base/java.lang.ProcessImpl.forkAndExec(Native Method)
at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:314)
at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:244)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1110)
... 3 more
command
is definitely available on my bash -
user@pc:~$ type command
command is a shell builtin
Why does the error occur?
Note that most other similar queries (there are plenty on SO) got solved via syntactic corrections or bad file paths, and don't apply here.
Env:
JDK 17 on Ubuntu 20.04.5 LTS
Java code:
import java.io.IOException;
//rough.java
public class rough {
public static void main(String[] args) throws IOException {
new ProcessBuilder("command","-v","date").start();
}
}
CodePudding user response:
Your first sentence already has the solution:
[…] using the
command
shell builtin […]
ProcessBuilder
execs processes directly and does not invoke a shell. And since a shell-builtin is a functionality provided by the shell and not a binary, it cannot be invoked (directly) with ProcessBuilder
.
If you want to run a shell, you need to do so explicitly:
new ProcessBuilder("sh", "-c", "command -v date").start();