I am trying to redirect output of a process started with the help of ProcessBuilder using following code
ProcessBuilder pb = new ProcessBuilder("/myScript >> /myLogFile 2>&1 <& - &");
Map<String, String> env = pb.environment();
env.clear();
env.put("var1", "val1");
env.put("var2", "val2");
pb.redirectErrorStream(true);
Process p = pb.start();
But it failed with exception
Exception in thread "main"
java.io.IOException: Cannot run
program
"/myScript >>
/myLogFile
2>&1 <& - &": java.io.IOException:
error=2, No such file or directory at
java.lang.ProcessBuilder.start(ProcessBuilder.java:460)
It works fine when I just pass "/myScript"
Script is perl, any suggestions/coments on why it is failing?
I tried passing all of them as seperate arguments like new ProcessBuilder("/myScript",">>","/myLogFile"), it executes but it does not redirect to log file and also it does not take envVars.
Shell redirection operators are unknown to ProcessBuilder. Put your command in a shell script and execute it, as shown here. Alternatively, use bash -c, as shown here.
As you specified, from Java7 you can keep using ProcessBuilder with the only executable file as parameter and redirect/intercept its output stream, using redirectInput() redirectOutput() and redirectError() from ProcessBuilder class.
Related
I have a java program that does some preparation and then invokes Jekyll on the content it's prepared. Jekyll is a Ruby program installed on the local PC as a gem. On windows and linux, no problem, but when running on OSX, under the eclipse debugger, Jekyll doesn't run. Presumably this is because of interactive shell issues (Jekyll runs fine from the terminal).
Here's my java code:
DefaultExecutor exec = new DefaultExecutor(); // from org.apache.commons.exec
exec.setExitValue(0);
MyFilterHandler pumpHandler = new MyFilterHandler();
exec.setWorkingDirectory(new File("/Users/grahamegrieve/temp/igs/swissnoso/temp/pages"));
ProcessBuilder processBuilder = new ProcessBuilder(new String("bash -c jekyll build --destination /Users/grahamegrieve/temp/igs/swissnoso/output"));
Map<String, String> env = processBuilder.environment();
Map<String, String> vars = new HashMap<>();
vars.putAll(env);
String path = "/Users/grahamegrieve/.gem/ruby/3.1.0/bin:/Users/grahamegrieve/.gem/ruby/3.1.0/bin:/opt/homebrew/opt/ruby/bin:/Users/grahamegrieve/.nvm/versions/node/v17.4.0/bin:/opt/homebrew/bin:/opt/homebrew/sbin:"+env.get("PATH");
vars.put("PATH", path);
exec.execute(org.apache.commons.exec.CommandLine.parse("bash -c -i jekyll build --destination /Users/grahamegrieve/temp/igs/swissnoso/output"), vars);
this results in the following output from the process:
A subcommand is required.
followed by Jekyll's standard documentation - so Jekyll is running but not getting the parameters. The same thing happens in terminal:
➜ ~ bash -c jekyll build --destination /Users/grahamegrieve/temp/igs/swissnoso/output
A subcommand is required.
jekyll 4.2.1 -- Jekyll is a blog-aware, static site generator in Ruby
Usage:
jekyll <subcommand> [options]
In the terminal, I can do this:
➜ ~ bash -c 'jekyll build --destination /Users/grahamegrieve/temp/igs/swissnoso/output'
Configuration file: none
Source: /Users/grahamegrieve
Destination: /Users/grahamegrieve/temp/igs/swissnoso/output
Incremental build: disabled. Enable with --incremental
Generating...
so the parameters work fine when the entire command is wrapped in ''. But putting '' (or "") in the java code results in
Jekyll: bash: jekyll build --destination /Users/grahamegrieve/temp/igs/swissnoso/output: No such file or directory
As far as I can tell, that means there is no file with the name 'Jekyll build ...'.
So I don't know how to invoke Jekyll from my java code on OSX. Is it possible?
The answer is over here: execute shell command with org.apache.commons.exec.DefaultExecutor
It's to do with the way CommandLine works, and interacts with Bash.
DefaultExecutor exec = new DefaultExecutor(); // from org.apache.commons.exec
exec.setExitValue(0);
MyFilterHandler pumpHandler = new MyFilterHandler();
exec.setWorkingDirectory(new File("/Users/grahamegrieve/temp/igs/swissnoso/temp/pages"));
ProcessBuilder processBuilder = new ProcessBuilder(new String("bash -c jekyll build --destination /Users/grahamegrieve/temp/igs/swissnoso/output"));
Map<String, String> env = processBuilder.environment();
Map<String, String> vars = new HashMap<>();
vars.putAll(env);
String path = "/Users/grahamegrieve/.gem/ruby/3.1.0/bin:/Users/grahamegrieve/.gem/ruby/3.1.0/bin:/opt/homebrew/opt/ruby/bin:/Users/grahamegrieve/.nvm/versions/node/v17.4.0/bin:/opt/homebrew/bin:/opt/homebrew/sbin:"+env.get("PATH");
vars.put("PATH", path);
CommandLine cmd = new CommandLine("bash").addArgument("-c").addArgument("Jekyll build --destination /Users/grahamegrieve/temp/igs/swissnoso/output", false);
exec.execute(cmd, vars);
I am trying to run a batch file using java. The batch file in turn runs a python program. So i should wait till the batch file is done and then proceed with my program.
Problems facing:
I could not run batch file in background. I am able to run it only via start
Process p = Runtime.getRuntime().exec("cmd /c start c://GCTI//IA/QAART//testercheck.bat");
once the batch file ran, it is not closing automatically.
Batch file
"C:\Python27\python.exe" -i "C:\GCTI\IA\QAART\tester\test_monitor.py" -init "C:\GCTI\IA\EpiPhone\Dispatcher6\init\INIT_Designer_QAART_Dispatcher_Chat.PY" -testlist "C:\GCTI\IA\ASR_QAART\dat files\ChatAutomation\chat.dat" 23
Can you please help me to run this batch ile in background?
You don't need the batch file. You can execute the Python program directly from Java code using class java.lang.ProcessBuilder.
ProcessBuilder pb = new ProcessBuilder("C:\\Python27\\python.exe",
"-i",
"C:\\GCTI\\IA\QAART\\tester\\test_monitor.py",
"-init",
"C:\\GCTI\\IA\\EpiPhone\\Dispatcher6\\init\\INIT_Designer_QAART_Dispatcher_Chat.PY",
"-testlist",
"C:\\GCTI\\IA\\ASR_QAART\\dat files\\ChatAutomation\\chat.dat",
"23");
Process p = pb.start();
int result = p.waitFor();
Refer to other methods in class ProcessBuilder for handling the output of the Python script, for example method inheritIO
I can execute usual commands on Linux, wrapped by the processBuilder. But I'm currently trying to run the minecraft server like in the following example, with some variable set before the command, and it fails with an exception.
final ProcessBuilder processBuilder = new ProcessBuilder("LD_LIBRARY_PATH=. ./bedrock_server");
processBuilder.directory(MC_PAL_LOCATION_DIR.toFile());
process = processBuilder.start();
Exception:
java.io.IOException: Cannot run program "LD_LIBRARY_PATH=. ./bedrock_server" (in directory "/home/user/Desktop/minecraft_bedrock_server_t"): error=2, No such file or directory
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
at controller.Server.startMinecraftServer(Server.java:91)
at controller.Server.start(Server.java:58)
at Bootstrapper.bootServer(Bootstrapper.java:67)
at Bootstrapper.main(Bootstrapper.java:30)
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:247)
at java.lang.ProcessImpl.start(ProcessImpl.java:134)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
... 4 more
Exception in thread "Thread-0" java.lang.NullPointerException
at controller.ConsoleInput.run(ConsoleInput.java:16)
at java.lang.Thread.run(Thread.java:748)
Is there any possibility to use the processBuilder for such commands? The command works if I paste it directly to the terminal.
Link to server: https://minecraft.net/en-us/download/server/bedrock/
Command: LD_LIBRARY_PATH=. ./bedrock_server
You can't use bash shell commands like that without bash. But you can manipulate the environment yourself programmatically. Like,
final ProcessBuilder processBuilder = new ProcessBuilder("./bedrock_server");
processBuilder.environment().put("LD_LIBRARY_PATH", ".");
processBuilder.directory(MC_PAL_LOCATION_DIR.toFile());
process = processBuilder.start();
As #ElliottFrisch pointed out, you cannot use shell command without bash, therefore you either add LD_LIBRARY_PATH to environment map or execute bash:
final ProcessBuilder processBuilder = new ProcessBuilder("bash", "-c", "LD_LIBRARY_PATH=. ./bedrock_server");
processBuilder.directory(MC_PAL_LOCATION_DIR.toFile());
process = processBuilder.start();
I am using ProcessBuilder to run a Linux command on a server:
ProcessBuilder pb = new ProcessBuilder("/usr/bin/printf %b", sendMessage,
URL, " #serendipity | /usr/bin/perl /usr/local/bin/foo/bar -u nagios -s");
I am trying to broadcast a message that will be piped to a paging system called bar. But when executing the jar file on the server, I constantly get this:
java.io.IOException: Cannot run program "/usr/bin/printf %b": error=2, No such file or directory
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
at sms_serendipity.sms_serendipity.SmsSendMessage.sendMessage(SmsSendMessage.java:59)
at sms_serendipity.sms_serendipity.SmsSendMessage.randomizeLinks(SmsSendMessage.java:48)
at sms_serendipity.sms_serendipity.SmsParseWeb.regexHttp(SmsParseWeb.java:103)
at sms_serendipity.sms_serendipity.SmsParseWeb.parseXML(SmsParseWeb.java:77)
at sms_serendipity.sms_serendipity.SmsParseWeb.locateWebAudio(SmsParseWeb.java:44)
at sms_serendipity.sms_serendipity.mainClass.main(mainClass.java:11)
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:247)
at java.lang.ProcessImpl.start(ProcessImpl.java:134)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
... 6 more
It's my first time using ProcessBuilder (I have also tried with Runtime.exec() as well). Can someone tell me what I may do to correct the command I am trying to run?
Read the error message carefully: you try to execute the program /usr/bin/printf %b which of course does not exist.
The program is called /usr/bin/printf.
I have figured out a way of getting this working. It took a bit of experimenting but here is what I did.
ProcessBuilder pb = new ProcessBuilder(
"/bin/dash",
"-c",
"/usr/bin/perl /usr/local/bin/foo/bar -u nagios -s " + sendMessage + URL + fooUser,
"/bin/echo");
I had it log the stdout to a text file and confirmed that the broadcast works.
I have a python compiled script (script.pyc , I haven't the .py file)that work well from my windows command prompt, and I want to execute it from my Java's application.
I tried to use runtime() method :
Runtime runtime = Runtime.getRuntime();
runtime.exec(new String[] {"C:\\toto\\tools\\script.pyc" ,"arg","arg2" });
but I get an error :
Exception in thread "main" java.io.IOException: Cannot run program "C:\Nuance\VoCon Hybrid\SDK_v4_3\tools\clctodict.pyc": CreateProcess error=193, %1 n?est pas une application Win32 valid
The script work well in my terminal ("arg" is a txt file, "arg2" is the output name, and the script does its job without any problem).
I also try to launch my script with getDesktop() :
File fie = new File("C:\\toto\\tools\\script.pyc" ,"arg","arg2");
Desktop.getDesktop().open(fie);
There is no problem, but I can't add argument, so I can just see a terminal windows opening during a few second before disappearing instantly.
I have also tried to use JPython, without success too (maybe we can't use methode "execfile" on a .pyc????)
You can do something like
Process p = Runtime.getRuntime().exec(new String[]{"python.exe" ... other args)
Then you can invoke p.waitFor() to wait for the end of the process and p.exitValue() to test if the program exited successfully.
You can also get the output stream via p.getOutputStream() to retrieve the text printed by your python script
Please refer to the class documentation for further information : http://docs.oracle.com/javase/6/docs/api/java/lang/Process.html
Just like you need a jvm to run a .class, you need a python interpreter to run a .pyc.
Try something like:
runtime.exec(new String[] {"c:\\Python26\\bin\\python.exe", "C:\\toto\\tools\\script.pyc" ,"arg","arg2" });