How to execute bash commands in Java (Raspberry pi) - java

I dont know why, but I can only execute a very small pallet of commands on my Raspberry 3B from code (I cane even execute echo). For some reason, 99% of the commands that you would normally be able to do in the terminal itself, you cant do from code.
Example: I execute this java code:
Runtime.getRuntime().exec("echo hi");
And I get this:
`java.io.IOException: Cannot run program "echo hi": error=2, No such file or directory
Is there a PATH configuration that I dont have access to in java code? why cant I execute any commands to the raspberry pi from code?

I've written some example that uses the exec() call. There are other methods to start processes from within Java (ProcessBuilder is the keyword here), but this example is relatively easy to understand:
import java.util.*;
import java.io.*;
import java.text.*;
public class X {
public static void main(String argv[])
{
String args[] = { "/bin/bash", "-c", "uptime" };
try {
Process p = Runtime.getRuntime().exec(args);
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = in.readLine();
while (line != null) {
System.out.println("Found: " + line);
line = in.readLine();
}
} catch (Exception e) {
System.err.println("Some error occured : " + e.toString());
}
}
}
Basically the program executes the command line /bin/bash -c uptime; just an uptime would have done the same, but I wanted to show how to work with command line arguments for the program to start.

Related

Java calls Powershell using proc.waitFor(), cannot get correct return code

I'm having a problem with Java calling a powershell script.
This is the sample testing Java program that I'm using:
import java.util.*;
import java.io.*;
import java.sql.*;
import java.text.*;
public class testJava
{
public static void main (String[] args) {
StringBuffer sb = new StringBuffer();
String cmd = "";
Process proc;
int exitVal;
try {
sb = new StringBuffer();
sb.append("powershell C:\\test\\return_sth.ps1");
cmd = sb.toString();
proc = Runtime.getRuntime().exec(cmd);
proc.getOutputStream().close();
exitVal = proc.waitFor();
System.out.println("exitVal = " + exitVal);
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
The powershell script "return_sth.ps1" is:
exit 123
I find that I cannot get "123" in the Java's variable "exitVal".
Instead, I get exitVal = "1".
Actually, all exit codes OTHER THAN 0 (including negative codes like -1) from the powershell script becomes "1" in exitVal.
I would like to know how to properly capture the exit code in Java from the powershell script. After testing, I have found an alternative way that CAN achieve the goal, but I think it looks a bit clumsy and not clever:
Replace the Java's sb.append line with
sb.append("powershell.exe -Command \"C:\\test\\return_sth.ps1;exit $lastexitcode\"");
Is my new way a way to go? Or is there a nicer, more tidy calling method to get the exit code from powershell?
Please advise, thanks!
Exit code are be absorbed due to the chain of the calls from java -> powershell -> script forked executions if you use the -command argument, however for -File argument, the exit-code / errorlevel is passed directly over to the parent process.
With regards, I recommend to use -file to passthru the exitcode properly in your case:
powershell -file C:\test\return_sth.ps1
On the other hand, if you wish to use the -command parameter your example is perfectly fine too.

unexpected result while communicating with another process's stdin

My project directory has the 3 files below.
rndbet/rndbet.py
while True:
s = input()
if s == "exit":
exit()
else:
print("I'm rndbet: " + s)
rndbet/start
python3 rndbet.py
mjhd.java
import java.io.PrintStream;
import java.util.Scanner;
public class mjhd {
public static void main(String[] args) throws Exception {
Process process = new ProcessBuilder("bash", "-c", "cd rndbet&&./start").start();
new Thread(new Runnable() {
#Override
public void run() {
Scanner in = new Scanner(process.getInputStream());
while (in.hasNextLine()) {
System.out.println("<- rndbet: " + in.nextLine());
}
}
}).start();
Scanner in = new Scanner(System.in);
PrintStream out = new PrintStream(process.getOutputStream(), true);
while (true) {
out.println(in.nextLine());
} //this part is actually broken; it shouldn't be an infinite loop
//just for testing
}
}
When I type bash -c "cd rndbet&&./start" directly from the command line, below happens.
$ bash -c "cd rndbet&&./start"
hi
I'm rndbet: hi
exit
But running the java program behaves differently.
$ java mjhd
hi
<- rndbet: I'm rndbet: hi
exit
<- rndbet: I'm rndbet: exit
exit
<- rndbet: I'm rndbet: exit
So now the Python script doesn't get the exit command correctly. Please help me fix this problem.
I've just found a problem that when the Python script is run via Java, an extra character of ASCII value 13 is always appended at the end of the sent text. What is a possible fix?
Okay I found a simple answer.
Changing out.println(in.nextLine()); to out.print(in.nextLine() + '\n') works.

executing the customs command on linux with process builder in java

I've been struggling for a while now with this problem and i can't seem to fix it. i have tried ProcessBuilder for executing the custom command on linux terminal but its not working
Actually i have two .sh file setProto.sh and setTls.sh file which is used to set the environment.So for executing the command i need to run these two file first for each instance of linux terminal.Only then we can be able to run the custom command anloss on the same instance of linux terminal in which .sh file supposed to run.For some reason i'm not able to make it work what is the mistake in my code ? Here's the code.
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.ProcessBuilder.Redirect;
public class EngineTest {
public static void main(String[] args) {
try {
ProcessBuilder builder = new ProcessBuilder(
"/. setProto.sh",
"/. setTls.sh",
"/anloss -i ${TOOL_INPUT}/census_10000_col5.csv -d ${TOOL_DEF}/attr_all_def.txt -q k=14,dage=2 -g ${TOOL_RES}/census_100_col8_gen.csv");
builder.directory(new File(System.getenv("HOME") + "/PVproto/Base"));
File log = new File("log");
builder.redirectErrorStream(true);
builder.redirectOutput(Redirect.appendTo(log));
Process process = builder.start();
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line = "";
String output = "";
while ((line = bufferedReader.readLine()) != null) {
output += line + "\n";
}
System.out.println(output);
int exitValue = process.waitFor();
System.out.println("\n\nExit Value is " + exitValue);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Process does not by default execute in the context of a shell; therefore your shell scripts cannot be executed the way you tried.
ProcessBuilder pb =
new ProcessBuilder( "/bin/bash",
"-c",
". setProto.sh && . setTls.sh && /anloss -i ${TOOL_INPUT}/census_10000_col5.csv -d ${TOOL_DEF}/attr_all_def.txt -q k=14,dage=2 -g ${TOOL_RES}/census_100_col8_gen.csv" );
I am not sure about /anloss - it's unusual for a command to be in root's home /. (Also, the /. you had there in front of the shell scripts - what should they achieve?)
Later
Make sure to replace /anloss with an absolute pathname or a relative pathname relative to $HOME/PVproto/Base, e.g., if it is in this directory, use ./anloss, if it is in $HOME/PVproto/Base/SomeSub, use SomeSub/anloss, etc.
Also, if setProto.sh and . setTls.sh are not in $HOME/PVproto/Base, use an appropriate absolute or relative pathname. If they are, use ./setProto.sh and ./setTls.sh to avoid dependency on the setting of environment variable PATH.
I think you need to use Runtime.exec() for executing the commands on linux. I suppose you are executing your java code on linux machine where linux scripts needs to be run.
Below code snippet will help you in resolving it.
Process process = Runtime.getRuntime().exec(scriptWithInputParameters);
int exitCode = process.waitFor();
if (exitCode == 0) {
System.out.println("Executed successfully");
}
else {
System.out.println("Failed ...");
}
Please note you need to handle error and output stream in different threads to avoid buffer overflow.
If the above works for you then this article will help you further

Java Runtime.exec can not correctly execute JSTACK command

I'm attempting to execute jstack command using Runtime.exec but it seems there is an error but I can't find it out.
In addition, I can execute the following command in CMD and it works fine:
C:\Users\bob>"C:\Program Files\Java\jdk1.6.0_18\bin\jstack" 5540 > d:\s.log
Test class full text:
package test;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Test {
public static void main(String[] args) {
try {
Process process = Runtime.getRuntime().exec("\"C:\\Program Files\\Java\\jdk1.6.0_18\\bin\\jstack\" 5540 > d:\\s.log");
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while ((line = input.readLine()) != null) {
System.out.println(line);
}
int exitVal = process.waitFor();
System.out.println("Exited with code '" + exitVal + "'");
} catch (Exception e) {
System.out.println("Error.");
}
}
}
Output:
Usage:
jstack [-l] <pid>
(to connect to running process)
Options:
-l long listing. Prints additional information about locks
-h or -help to print this help message
Exited with code '1'
How can I solve this problem?
Thanks in advance.
the cause is your output redirection argument: > d:\\s.log
jstack actually receives that bit as extra arguments, fails to parse it, and prints out the error.
when you invoke the same command from the class (cmd.exe on windows) the shell itself recognizes the redirect command, strips it out of the command, and jstack only "sees" the pid argument.
you have 2 options to fix this:
dont call jstack.exe, call cmd.exe with an argument telling it to run jstack and redirect the output
drop the redirection bit and write the output to file yourself

Command line argument works in console, fails from within Runtime.getRuntime().exec

Trying to build a basic launcher for a java game. I'm building the proper command to run the application. When the following command executes in the launcher, the launcher closes as expected, but the command doesn't appear to work - either it doesn't work or the game launches and immediately crashes.
When I print this same command to the console and copy/paste it into console and execute manually, it works perfectly.
/**
*
*/
protected void launch(){
currentStatusMsg = "Launching...";
String cmd = "java -jar";
cmd += " -Djava.library.path=\"" +nativesDirectory.getAbsolutePath() + "\"";
cmd += " \""+applicationJar.getAbsolutePath() + "\"";
System.out.println(cmd);
try {
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(cmd);
//closeLauncher();
BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String line=null;
while((line=input.readLine()) != null) {
System.out.println(line);
}
int exitVal = pr.waitFor();
System.out.println("Exited with error code "+exitVal);
} catch(Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}
}
I tried adding something to read the output, but nothing is printed.
I was originally using the following format instead, but it has the same effect:
Process pr = Runtime.getRuntime().exec(new String[]{
"java",
"-Djava.library.path=\"" +nativesDirectory.getAbsolutePath() + "\"",
"-jar",
applicationJar.getAbsolutePath()});
Update I realized I was closing the launcher before allowing the debug code to run. The system only prints: "Exited with error code 1"
I finally was able to get the subprocess error to print. It states:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no lwjgl in java.library.path
However, it should be available because the command I'm executing includes the library path, and when this exact command is run manually, it works fine.
the java command launcher is not a shell. don't use quoting and space separated commands because it won't end well. put each argument into a separate String without any extra quoting, and use the exec(String[]) method.

Categories

Resources