Powershell script does not run in Java code - java

I have a simple script and I want to call it from my Java code. The script does not run properly.
The script is very simple:
mkdir 0000000;
public static void main(String[] args) throws Exception{
String path = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
String command = "C:\\test\\test.ps1";
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec(path + " " + command);
proc.destroy();
}
The dir "0000000" is not created. I use JDK 7, windows 10.
Any suggestion would be gratefully appreciated.

I changed the code as below and finally it worked!
public static void main(String[] args) throws Exception{
String path = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
String command1 ="cmd /c \"cd C:\\test && " + path + " /c .\\test.ps1\"";
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec(command1);
Thread.sleep(2000);
proc.destroy();
}

exec() runs the process asynchronously, so the subsequent proc.destroy() terminates it right away before it can do anything. If you run the program from an interactive shell simply removing proc.destroy() would mitigate the issue, but to actually fix it you need to wait for the external process to finish. You may also want to catch the exception exec() (or waitFor()) could throw.
import java.io.*;
public static void main(String[] args) throws Exception{
String path = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
String command = "C:\\test\\test.ps1";
Runtime runtime = Runtime.getRuntime();
try {
Process proc = runtime.exec(path + " " + command);
proc.waitFor();
} catch (Exception e) {
// do exception handling here
}
}

Related

Runtime.getRuntime().exec(command) doesn't work

I have a problem with executing command in Runtime.getRuntime().exec(command) on my linux DEV machine.
I'm trying to convert html content to mobi format using calibre but it doesn't work.
Even if I added log.warn to display what this process returns it shows nothing.
It works on my local machine where I do have Windows 10 and I read on the Internet that I should point out that command should be launched on linux so I added String[] cmd = {"bash", "-c", command}; but it still doesn't work.
My command looks like this:
/usr/src/calibre/ebook-convert /tmp/filesDirectory_mobi3970575619159760977/d7ed6792-b3cb-4761-bb6a-b9facf9e7a6c9250643820137116550.html /tmp/filesDirectory_mobi3970575619159760977/d7ed6792-b3cb-4761-bb6a-b9facf9e7a6c11909891397415910433.mobi
And here's my code:
#Override
public Document convert(Document document, DocumentFormat documentFormat) {
Document htmlDocument = htmlDocumentConverter.convert(document, documentFormat);
try {
log.info("Converting document from {} to {}", getSourceFormat().toString(), getTargetFormat().toString());
CalibreConfigData calibreData = calibreConfig.getConfigurationData(CalibreConversion.HTML_TO_MOBI);
Files.write(calibreData.getSourceFilePath(), htmlDocument.getContent());
String command = calibreData.getCalibreCommand();
String[] cmd = {"bash", "-c", command};
var r = Runtime.getRuntime().exec(cmd);
r.waitFor();
log.warn("Process: " + new String(r.getInputStream().readAllBytes(), StandardCharsets.UTF_8));
byte[] convertedFileAsBytes = Files.readAllBytes(calibreData.getConvertedFilePath());
// Files.deleteIfExists(calibreData.getSourceFilePath());
// Files.deleteIfExists(calibreData.getConvertedFilePath());
// Files.deleteIfExists(calibreData.getFilesDirectoryPath());
return new Document(convertedFileAsBytes);
} catch (InterruptedException | IOException e) {
log.error("Conversion failed due to problem: " + e);
throw new ConversionException("Conversion failed due to problem: " + e);
}
}
I checked created tempFiles and found out that file .html has content inside but file .mobi is empty even after executing above's command.
A main method of a Calibre conversion invoker could be as simple as the below:
public static void main(String[] args) {
try {
String[] command = { "/usr/src/calibre/ebook-convert", args[0], args[1] };
ProcessBuilder pb = new ProcessBuilder(command);
pb.inheritIO();
pb.start();
} catch (Throwable t) {
t.printStackTrace();
}
}

run git clone in Java getRuntime.exec() - use /bin/bash in linux - “no such file or directory” in error stream

I am trying to execute git clone in Java using Java's Runtime.getRuntime().exec() in Linux and the interpreter is /bin/bash. However, I get "no such file or directory" in error stream. I searched the stackoverflow and found no answer can solve my problem. Here is my program in Test.java:
import java.io.*;
public class Test {
public static void main(String[] args) throws IOException, InterruptedException {
String version = "10.1.1";
String repo_url = "https://github.com/postcss/postcss-url";
String directory = "./tmp";
String cmd = "\"/usr/bin/git clone --branch " + version + " " + repo_url + " --depth=1 " + directory + "\"";
// String cmd = "git -h";
String interpreter = "/bin/bash";
cmd = " -c "+ cmd;
System.out.println(interpreter + cmd);
Process process = Runtime.getRuntime().exec(new String[]{ interpreter, cmd });
print(process.getInputStream());
print(process.getErrorStream());
process.waitFor();
int exitStatus = process.exitValue();
System.out.println("exit status: " + exitStatus);
File[] files = new File(directory).listFiles();
System.out.println("number of files in the directory: " + files.length);
}
public static void print(InputStream input) {
new Thread(new Runnable() {
#Override
public void run() {
BufferedReader bf = new BufferedReader(new InputStreamReader(input));
String line = null;
try {
while ((line = bf.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println("IOException");
}
}
}).start();
}
}
./tmp is surely an empty directory. I use javac Test.java to compile the code and then run java Test. Besides, I tried sudo java Test and got the same result. I get output like this:
/bin/bash -c "/usr/bin/git clone --branch 10.1.1 https://github.com/postcss/postcss-url --depth=1 ./tmp"
exit status: 127
/bin/bash: -c "/usr/bin/git clone --branch 10.1.1 https://github.com/postcss/postcss-url --depth=1 ./tmp": No such file or directory
Exception in thread "main" java.lang.NullPointerException
at Test.main(Test.java:18)
When I use "git -h" or "ls", it works just fine. But, this command /bin/bash -c "/usr/bin/git clone --branch 10.1.1 https://github.com/postcss/postcss-url --depth=1 ./tmp" works in shell but failed in Java. How can I solve this problem?
You have to pass -c as a separate parameter, and you shouldn't add literal double quotes to the command:
new String[]{ "bash", "-c", "git clone ..." }
This is because spaces and quotes are shell syntax, and Runtime.exec doesn't invoke one to run the command (which happens to be a shell invocation, but that's unrelated)

How to have java run terminal commands on Mac? (Echo command)

How do you have java run commands on Mac? I see some examples of complex commands that is hard to follow. If I wanted to run a simple echo command from java, how would I do that? Not using osascript yet. Just want to see how you would send an echo from java to terminal.
public static void main(String[] args) throws IOException {
ProcessBuilder x = new ProcessBuilder("echo"," hi");
x.start();
}
This is the code I tried, but it does not work.
I think this question can help people who are trying to learn the basics of ProcessBuilder.
I am on Windows so the below code uses Windows echo. I hope you know the Mac echo command so that you can replace my command with yours.
import java.io.IOException;
import java.lang.ProcessBuilder;
public class PrcBldT2 {
public static void main(String[] args) {
// This command is for Windows operating system.
// For MacOS, try: new ProcessBuilder("echo", "hi")
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", "echo", "hi");
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
try {
Process p = pb.start();
int result = p.waitFor();
System.out.println("Exit status = " + result);
}
catch (IOException | InterruptedException x) {
x.printStackTrace();
}
}
}
Note that each word in the command is a separate string. The echo command output will be redirected to System.out.

Running Java Program in another Program gives error

I want to execute another Java program in my program. I have taken reference from here. For testing I have pasted same code as accepted answer shows.I have passed a simple HelloWorld program. Program compiles perfectly but gives Main class not found error.
Here is my code:
Server.java
public static void main(String args[]) {
try {
runProcess("javac D:\\HelloWorld.java");
runProcess("java D:\\HelloWorld");
} catch (Exception e) {
e.printStackTrace();
}
}
private static void printLines(String name, InputStream ins) throws Exception {
String line = null;
BufferedReader in = new BufferedReader(
new InputStreamReader(ins));
while ((line = in.readLine()) != null) {
System.out.println(name + " " + line);
}
}
private static void runProcess(String command) throws Exception {
Process pro = Runtime.getRuntime().exec(command);
printLines(command + " stdout:", pro.getInputStream());
printLines(command + " stderr:", pro.getErrorStream());
pro.waitFor();
System.out.println(command + " exitValue() " + pro.exitValue());
}
HelloWorld.java:
`public static void main(String args[]){
System.out.println("Hello World!");
}`
Output:
exitValue() 0 for javac
stderr: Error: Could not find or load main class D:\HelloWorld
exitValue() 1 for java
Compiling and running same program on CMD or IDE gives perfect output.
You want to start main from HelloWorld class? I think, in that case you should run program something like this:
java -cp 'D:\' HelloWorld
So, you need to specify ClassPath - 'D:\' and entry class name from classpath - HelloWorld.
Why try to do things the hard way? Use the inline compiler API and then simply execute the main() method on your new class after loading the class itself into your root classloader.

How to run Unix shell script from Java code?

It is quite simple to run a Unix command from Java.
Runtime.getRuntime().exec(myCommand);
But is it possible to run a Unix shell script from Java code? If yes, would it be a good practice to run a shell script from within Java code?
You should really look at Process Builder. It is really built for this kind of thing.
ProcessBuilder pb = new ProcessBuilder("myshellScript.sh", "myArg1", "myArg2");
Map<String, String> env = pb.environment();
env.put("VAR1", "myValue");
env.remove("OTHERVAR");
env.put("VAR2", env.get("VAR1") + "suffix");
pb.directory(new File("myDir"));
Process p = pb.start();
You can use Apache Commons exec library also.
Example :
package testShellScript;
import java.io.IOException;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
public class TestScript {
int iExitValue;
String sCommandString;
public void runScript(String command){
sCommandString = command;
CommandLine oCmdLine = CommandLine.parse(sCommandString);
DefaultExecutor oDefaultExecutor = new DefaultExecutor();
oDefaultExecutor.setExitValue(0);
try {
iExitValue = oDefaultExecutor.execute(oCmdLine);
} catch (ExecuteException e) {
System.err.println("Execution failed.");
e.printStackTrace();
} catch (IOException e) {
System.err.println("permission denied.");
e.printStackTrace();
}
}
public static void main(String args[]){
TestScript testScript = new TestScript();
testScript.runScript("sh /root/Desktop/testScript.sh");
}
}
For further reference, An example is given on Apache Doc also.
I think you have answered your own question with
Runtime.getRuntime().exec(myShellScript);
As to whether it is good practice... what are you trying to do with a shell script that you cannot do with Java?
I would say that it is not in the spirit of Java to run a shell script from Java. Java is meant to be cross platform, and running a shell script would limit its use to just UNIX.
With that said, it's definitely possible to run a shell script from within Java. You'd use exactly the same syntax you listed (I haven't tried it myself, but try executing the shell script directly, and if that doesn't work, execute the shell itself, passing the script in as a command line parameter).
Yes it is possible to do so. This worked out for me.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.omg.CORBA.portable.InputStream;
public static void readBashScript() {
try {
Process proc = Runtime.getRuntime().exec("/home/destino/workspace/JavaProject/listing.sh /"); //Whatever you want to execute
BufferedReader read = new BufferedReader(new InputStreamReader(
proc.getInputStream()));
try {
proc.waitFor();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
while (read.ready()) {
System.out.println(read.readLine());
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
Here is my example. Hope it make sense.
public static void excuteCommand(String filePath) throws IOException{
File file = new File(filePath);
if(!file.isFile()){
throw new IllegalArgumentException("The file " + filePath + " does not exist");
}
if(isLinux()){
Runtime.getRuntime().exec(new String[] {"/bin/sh", "-c", filePath}, null);
}else if(isWindows()){
Runtime.getRuntime().exec("cmd /c start " + filePath);
}
}
public static boolean isLinux(){
String os = System.getProperty("os.name");
return os.toLowerCase().indexOf("linux") >= 0;
}
public static boolean isWindows(){
String os = System.getProperty("os.name");
return os.toLowerCase().indexOf("windows") >= 0;
}
Yes, it is possible and you have answered it! About good practises, I think it is better to launch commands from files and not directly from your code. So you have to make Java execute the list of commands (or one command) in an existing .bat, .sh , .ksh ... files.
Here is an example of executing a list of commands in a file MyFile.sh:
String[] cmd = { "sh", "MyFile.sh", "\pathOfTheFile"};
Runtime.getRuntime().exec(cmd);
To avoid having to hardcode an absolute path, you can use the following method that will find and execute your script if it is in your root directory.
public static void runScript() throws IOException, InterruptedException {
ProcessBuilder processBuilder = new ProcessBuilder("./nameOfScript.sh");
//Sets the source and destination for subprocess standard I/O to be the same as those of the current Java process.
processBuilder.inheritIO();
Process process = processBuilder.start();
int exitValue = process.waitFor();
if (exitValue != 0) {
// check for errors
new BufferedInputStream(process.getErrorStream());
throw new RuntimeException("execution of script failed!");
}
}
As for me all things must be simple.
For running script just need to execute
new ProcessBuilder("pathToYourShellScript").start();
The ZT Process Executor library is an alternative to Apache Commons Exec. It has functionality to run commands, capturing their output, setting timeouts, etc.
I have not used it yet, but it looks reasonably well-documented.
An example from the documentation: Executing a command, pumping the stderr to a logger, returning the output as UTF8 string.
String output = new ProcessExecutor().command("java", "-version")
.redirectError(Slf4jStream.of(getClass()).asInfo())
.readOutput(true).execute()
.outputUTF8();
Its documentation lists the following advantages over Commons Exec:
Improved handling of streams
Reading/writing to streams
Redirecting stderr to stdout
Improved handling of timeouts
Improved checking of exit codes
Improved API
One liners for quite complex use cases
One liners to get process output into a String
Access to the Process object available
Support for async processes ( Future )
Improved logging with SLF4J API
Support for multiple processes
This is a late answer. However, I thought of putting the struggle I had to bear to get a shell script to be executed from a Spring-Boot application for future developers.
I was working in Spring-Boot and I was not able to find the file to be executed from my Java application and it was throwing FileNotFoundFoundException. I had to keep the file in the resources directory and had to set the file to be scanned in pom.xml while the application was being started like the following.
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
<include>**/*.sh</include>
</includes>
</resource>
</resources>
After that I was having trouble executing the file and it was returning error code = 13, Permission Denied. Then I had to make the file executable by running this command - chmod u+x myShellScript.sh
Finally, I could execute the file using the following code snippet.
public void runScript() {
ProcessBuilder pb = new ProcessBuilder("src/main/resources/myFile.sh");
try {
Process p;
p = pb.start();
} catch (IOException e) {
e.printStackTrace();
}
}
Hope that solves someone's problem.
Here is an example how to run an Unix bash or Windows bat/cmd script from Java. Arguments can be passed on the script and output received from the script. The method accepts arbitrary number of arguments.
public static void runScript(String path, String... args) {
try {
String[] cmd = new String[args.length + 1];
cmd[0] = path;
int count = 0;
for (String s : args) {
cmd[++count] = args[count - 1];
}
Process process = Runtime.getRuntime().exec(cmd);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
try {
process.waitFor();
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
while (bufferedReader.ready()) {
System.out.println("Received from script: " + bufferedReader.readLine());
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
System.exit(1);
}
}
When running on Unix/Linux, the path must be Unix-like (with '/' as separator), when running on Windows - use '\'. Hier is an example of a bash script (test.sh) that receives arbitrary number of arguments and doubles every argument:
#!/bin/bash
counter=0
while [ $# -gt 0 ]
do
echo argument $((counter +=1)): $1
echo doubling argument $((counter)): $(($1+$1))
shift
done
When calling
runScript("path_to_script/test.sh", "1", "2")
on Unix/Linux, the output is:
Received from script: argument 1: 1
Received from script: doubling argument 1: 2
Received from script: argument 2: 2
Received from script: doubling argument 2: 4
Hier is a simple cmd Windows script test.cmd that counts number of input arguments:
#echo off
set a=0
for %%x in (%*) do Set /A a+=1
echo %a% arguments received
When calling the script on Windows
runScript("path_to_script\\test.cmd", "1", "2", "3")
The output is
Received from script: 3 arguments received
It is possible, just exec it as any other program. Just make sure your script has the proper #! (she-bang) line as the first line of the script, and make sure there are execute permissions on the file.
For example, if it is a bash script put #!/bin/bash at the top of the script, also chmod +x .
Also as for if it's good practice, no it's not, especially for Java, but if it saves you a lot of time porting a large script over, and you're not getting paid extra to do it ;) save your time, exec the script, and put the porting to Java on your long-term todo list.
I think with
System.getProperty("os.name");
Checking the operating system on can manage the shell/bash scrips if such are supported.
if there is need to make the code portable.
String scriptName = PATH+"/myScript.sh";
String commands[] = new String[]{scriptName,"myArg1", "myArg2"};
Runtime rt = Runtime.getRuntime();
Process process = null;
try{
process = rt.exec(commands);
process.waitFor();
}catch(Exception e){
e.printStackTrace();
}
Just the same thing that Solaris 5.10 it works like this ./batchstart.sh there is a trick I don´t know if your OS accept it use \\. batchstart.sh instead. This double slash may help.
for linux use
public static void runShell(String directory, String command, String[] args, Map<String, String> environment)
{
try
{
if(directory.trim().equals(""))
directory = "/";
String[] cmd = new String[args.length + 1];
cmd[0] = command;
int count = 1;
for(String s : args)
{
cmd[count] = s;
count++;
}
ProcessBuilder pb = new ProcessBuilder(cmd);
Map<String, String> env = pb.environment();
for(String s : environment.keySet())
env.put(s, environment.get(s));
pb.directory(new File(directory));
Process process = pb.start();
BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedWriter outputReader = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
int exitValue = process.waitFor();
if(exitValue != 0) // has errors
{
while(errReader.ready())
{
LogClass.log("ErrShell: " + errReader.readLine(), LogClass.LogMode.LogAll);
}
}
else
{
while(inputReader.ready())
{
LogClass.log("Shell Result : " + inputReader.readLine(), LogClass.LogMode.LogAll);
}
}
}
catch(Exception e)
{
LogClass.log("Err: RunShell, " + e.toString(), LogClass.LogMode.LogAll);
}
}
public static void runShell(String path, String command, String[] args)
{
try
{
String[] cmd = new String[args.length + 1];
if(!path.trim().isEmpty())
cmd[0] = path + "/" + command;
else
cmd[0] = command;
int count = 1;
for(String s : args)
{
cmd[count] = s;
count++;
}
Process process = Runtime.getRuntime().exec(cmd);
BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedWriter outputReader = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
int exitValue = process.waitFor();
if(exitValue != 0) // has errors
{
while(errReader.ready())
{
LogClass.log("ErrShell: " + errReader.readLine(), LogClass.LogMode.LogAll);
}
}
else
{
while(inputReader.ready())
{
LogClass.log("Shell Result: " + inputReader.readLine(), LogClass.LogMode.LogAll);
}
}
}
catch(Exception e)
{
LogClass.log("Err: RunShell, " + e.toString(), LogClass.LogMode.LogAll);
}
}
and for usage;
ShellAssistance.runShell("", "pg_dump", new String[]{"-U", "aliAdmin", "-f", "/home/Backup.sql", "StoresAssistanceDB"});
OR
ShellAssistance.runShell("", "pg_dump", new String[]{"-U", "aliAdmin", "-f", "/home/Backup.sql", "StoresAssistanceDB"}, new Hashmap<>());

Categories

Resources