I want to execute telnet and msh in a shell on Linux one after another sequentially. I am able to execute telnet command, but not msh command using the below code in Java:
List<String> commands = new ArrayList<String>();
commands.add("/bin/bash");
commands.add("-c");
commands.add("telnet 10.x.x.x 1234");
commands.add("msh");
ProcessBuilder pb = new ProcessBuilder(commands);
pb.directory(new File("/home/user"));
pb.redirectErrorStream(true);
Process process = pb.start();
// Read output
StringBuilder out = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(
process.getInputStream()));
String line = null, previous = null;
while ((line = br.readLine()) != null) {
if (!line.equals(previous)) {
previous = line;
out.append(line).append('\n');
System.out.println(line);
}
}
// Check result
if (process.waitFor() == 0) {
System.out.println("Success executing telnet command!");
System.exit(0);
}
System.err.println(commands);
System.err.println(out.toString());
System.exit(1);
Any help on this is highly appreciated.
You should have two different commands to execute both in sequence like below:-
String[] command_telnet ={"\path\to\telnet", "10.x.x.x 1234"};
String[] command_msh ={"\path\to\msh", "parameter"};
ProcessBuilder pb_telnet = new ProcessBuilder(commands);
pb_telnet.directory(new File("/home/user/telnet_output.txt"));
pb_telnet.redirectErrorStream(true);
Process process_tel = pb_telnet.start();
Do the same for command_msh. This approach will be easy for you to debug as you will get the command output in /home/user/msh_output.txt
What you are currently having Java execute is the following (more or less; the following can be executed in a Shell, Java directly invokes a process):
/bin/bash -c 'telnet 10.x.x.x 1234' 'msh'
This leads to Bash executing telnet, because that is the argument to the -c flag, and the msh argument will be ignored: Bash doesn't know what to do with it.
There are two possible solutions.
Solution 1: let Bash execute the two commands sequentially.
For this to work, you want to execute something along the following lines
/bin/bash -c 'telnet 10.x.x.x 1234; msh'
which translates to you having to merge the last two strings in your commands list. For example,
commands.add("telnet 10.x.x.x 1234; msh");
Instead of using ; you can also use &&. See Unix.SE for more details.
Disadvantage: Bash will let you know the exit code of the last process only. In the case of using &&, having the first command fail will not even execute the second one.
Solution 2: create a separate process in Java for each.
For this solution, you'll essentially have to repeat all your code for the invocation of msh. I'd recommend wrapping it in a function if you go this route. Simply use {"/bin/bash", "-c", "telnet 10.x.x.x 1234"} as the list of commands for one invocation, and {"/bin/bash", "-c", "msh"} for the other invocation.
Advantage is that you have more control in your Java program, instead of having Bash handle things. Disadvantage is you starting two separate processes, but Bash might do that under the hood anyway.
Side remark: you can directly execute telnet and msh without invoking Bash and telling it to run telnet or msh for you. That might be even nicer, and more efficient.
Related
I was developing my spring boot server on Windows. Now I have upgraded to Ubuntu 20.04.
the project executes a python script which should return a result as a txt file with this command:
python3 -c "from main import *;main(function,'/tmp/execution12480676806364930620/executionResponse.txt')"
Thanks to this code:
List<String> items = Arrays.asList(project.getExecutorType().buildAndGetExecutionCommandByProject(project));
ProcessBuilder pb = new ProcessBuilder(items);
pb.directory(new File(project.getPath()));
Process p = pb.start();
p.waitFor(5, TimeUnit.SECONDS);
when I print in the console the array passed in the Item variable:
[python3, -c, "from main import *;main(function, '/tmp/execution12480676806364930620/executionResponse.txt')"]
and the path of the array passed in pb.directory :
/tmp/execution12480676806364930620
My problem is that the project is not running and returning nothing.
when i go to the folder and run the same command from terminal everything works.
And that on windows 10 this same process worked fine.
Looking at similar issues I modified my code like this but it doesn't change anything:
List<String> items = Arrays.asList(project.getExecutorType().buildAndGetExecutionCommandByProject(project));
ProcessBuilder pb = new ProcessBuilder();
pb.command(items);
pb.redirectErrorStream(true);
pb.directory(new File(project.getPath()));
Process p = pb.start();
p.waitFor(5, TimeUnit.SECONDS);
What am I doing wrong?
Edit :
My command for read outputs :
private String inputStreamToString(InputStream inputStream){
return new BufferedReader(
new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines()
.collect(Collectors.joining("\n"));
}
And I call it like that :
System.out.println(this.inputStreamToString(p.getErrorStream()));
System.out.println(this.inputStreamToString(p.getInputStream()));
What works, when I just run "python main.py" I get the errors and print them out.
I can easily add the command at the end of the main file but I don't understand why the python -c "..." is not working? I am not receiving any errors ... I manage several languages and this could be a problem for me later
Aha! On closer inspection I think you're right it's not executing anything (and thus not producing any output either normal or error for you to see).
You don't show how the array of strings is created, but your printout suggests you have actually put quotemarks in the third string. That's wrong. When you give the shell command line python -c "import this; dothat" the shell uses the quotemarks to control parsing of this command line, but it does not pass them to the python process; the args passed to the python process (shown vertically for clarity, and omitting the argv[0]=program used in C but omitted in Java) are actually
-c
import this; dothat
If you pass an argument actually containing quotemarks like
-c
"import this; dothat"
then python doesn't execute the commands import and dothat; instead it evaluates the string literal "import this; dothat" and (since it isn't running interactively) discards the result.
Try not including, or removing, the " at the beginning and end. But leave the ' inside the string value because you do want python to receive those.
I am using the process class to run this command
/sdcard/file1.mpg /sdcar/file2.mpg > /sdcard/out.mpg
Here is how I am trying to do it:
Process processx = Runtime.getRuntime().exec(new String[] {"cat","/sdcard/file1.mpg /sdcard/file2.mpg > /sdcard/out.mpg" });
BufferedReader in = new BufferedReader(new InputStreamReader(processx.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
// Waits for the command to finish.
processx.waitFor();
The command works from terminal but not when I try the above, can anyone see why?
Redirection (>) is not the OS feature. This is a feature of shell. To make it working from java you have to run something like the following:
/bin/sh yourcommand > yourfile
i.e. in your case:
/bin/sh cat /sdcard/file1.mpg /sdcard/file2.mpg > /sdcard/out.mpg
BUT could you please explain me why are you doeing this? Do you understand that this command is exact equivalent of cp /sdcard/file1.mpg /sdcard/file2.mpg /sdcard/out.mpg that can be coded in pure java without running any command line? Unless you have special reasons go on it! Write pure java code when it is possible. It is easier to debug, support and maintain.
There's absolutely no reason to use 'cat' to do this. It's not a supported or encouraged mechanism on Android, and there's no reason to launch a new executable to do what you can easily do in java code, by reading in one file and writing it out to the other.
For the record, you are trying to do a shell redirection, and that will not work since you are not executing a shell.
im using this small code to execute "cat" command and most of shell commands:
String[] cmdline = { "sh", "-c", "cat /sdcard/file1 >> /sdcard/file2" };
try {
Runtime.getRuntime().exec(cmdline);
} catch (Exception s) {
finishAffinity();
}
It's not the first time I have tried to execute a system command from Java; but this time it turns out to be very hard. I have a script that executes just fine from the terminal. It reads input from a file (input.txt), it processes it and exports the result in another file (ouput.txt). The whole thing lasts no more than 1sec. But, when I try to execute it from Java, it gets stuck and never finishes. This is my code:
Process p = new ProcessBuilder("./runCalculator.sh").start();
p.waitFor();
I have also tried with Runtime.getRuntime().exec("./runCalculator.sh") but all the same. I've read both the InputStream and the ErrorStream of the process. The error stream returns nothing but a message like "Starting Calculation..."
Any ideas?
You need to use the following code:
ProcessBuilder pb = new ProcessBuilder();
pb.command("bash", "-c", "./runCalculator.sh");
Process process = pb.start();
int retValue = process.waitFor();
You likely need to invoke the unix command interpreter/processor for this to work. Please see: When Runtime.exec() won't.
Try this:
Process p = new ProcessBuilder("sh ./runCalculator.sh").start();
Another, simplier solution is that you can open program by entering the name of the program (this assumes that program is installed) instead of creating script and calling it.
Note that the name of the program isn't always what you see in Gnome's menu, for example Gnome's calculator is "gnome-calculator". Regarding this facts, you can run calculator by the folowing line:
Process p = Runtime.getRuntime().exec("gnome-calculator");
In that case you don't have a need for any sh scripts (in your case runCalculator.sh).
My aim with this project was to have a remote command prompt feel with Java. Using TCP/IP sockets, I was aiming to run a command prompt process on one computer, and virtually transmit all control to the other side. I immediately stumbled over Runtime.getRuntime().exec() and Process objects, etc. I've solved my problem about halfway. With my remote command prompt, I can run a single command, gather the output, and send it back to the other side. The problem is, I can only seem to run one command per command prompt instance. This won't do (with situations where I need to change directory and THEN run a command, etc). I've stripped all socket/networking programming from this situation to show you (and to create an easier testing environment for me).
import java.io.*;
public class testingProgram {
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
StringBuilder inputMessage = new StringBuilder();
String resultData;
try {
Process pr = rt.exec("cmd.exe /c net user");
BufferedReader processInput = new BufferedReader(new InputStreamReader(pr.getInputStream()));
BufferedReader errorProcessInput = new BufferedReader(new InputStreamReader(pr.getErrorStream()));
PrintWriter processOut = new PrintWriter(pr.getOutputStream());
while( (resultData = processInput.readLine()) != null ) {
inputMessage.append(resultData + "\n");
}
resultData = inputMessage.toString();
System.out.print(resultData);
} catch(IOException e) {
} //catch(InterruptedException e) {
//}
}
}
I have a lot more, but this is where my problem is. I can customize the command "net user" with a simple variable and message from the socketstream, so that's not my problem. My problem is that I need to create an ongoing command prompt instance, retaining all redirections of the input/output. Basically, I would like to be able to send another command AFTER "net user".
I have gathered and redirected the output stream. I want to be able to do something like:
processOut.write("net user");
I want to be able to use this, have the command prompt run the command, and retain the output (whether it be from the errorStream OR the inputStream).
I just need some more direction on how to go about doing this.
You should look into multi threading. What you basically want is a thread which keeps running and maintaining the rt.
Like this:
String commandLine;
while ((commandLine = System.in.readline()) != 'q') {
Process pc = rt.exec(commandLine);
}
For further reference on multithreading:
http://download.oracle.com/javase/tutorial/essential/concurrency/procthread.html
You problem is that your program terminates after one call.
cheers
You're telling the command interpreter to terminate. Remove the /C after cmd.exe.
cmd /?
Starts a new instance of the Windows command interpreter
CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V:OFF]
[[/S] [/C | /K] string]
/C Carries out the command specified by string and then terminates
/K Carries out the command specified by string but remains
...
I want to exceute a simple command which works from the shell but doesn't work from Java.
This is the command I want to execute, which works fine:
soffice -headless "-accept=socket,host=localhost,port=8100;urp;"
This is the code I am excecuting from Java trying to run this command:
String[] commands = new String[] {"soffice","-headless","\"-accept=socket,host=localhost,port=8100;urp;\""};
Process process = Runtime.getRuntime().exec(commands)
int code = process.waitFor();
if(code == 0)
System.out.println("Commands executed successfully");
When I run this program I get "Commands executed successfully".
However the process is not running when the program finishes.
Is it possible that the JVM kills the program after it has run?
Why doesn't this work?
I'm not sure if I'm not mistaken, but as far as I see you're generating the commands but never passing them to the "execute" method... you're executing "".
Try using Runtime.getRuntime().exec(commands) =)
I would like to say how I solved this.
I created a sh script that basically run the command of soffice for me.
Then from Java I just run the script, and it works fine, like this:
public void startSOfficeService() throws InterruptedException, IOException {
//First we need to check if the soffice process is running
String commands = "pgrep soffice";
Process process = Runtime.getRuntime().exec(commands);
//Need to wait for this command to execute
int code = process.waitFor();
//If we get anything back from readLine, then we know the process is running
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
if (in.readLine() == null) {
//Nothing back, then we should execute the process
process = Runtime.getRuntime().exec("/etc/init.d/soffice.sh");
code = process.waitFor();
log.debug("soffice script started");
} else {
log.debug("soffice script is already running");
}
in.close();
}
I also kill the soffice process by calling this method:
public void killSOfficeProcess() throws IOException {
if (System.getProperty("os.name").matches(("(?i).*Linux.*"))) {
Runtime.getRuntime().exec("pkill soffice");
}
}
Note that this only works in Linux.
I believe you aren't handling quoting correctly. The original sh command line includes double quotes to prevent the shell interpreting the semicolons. The shell strips them off before the soffice process sees them.
In your Java code the shell will never see the arguments, so the extra double quotes (escaped with backslashes) are not needed - and they are probably confusing soffice.
Here's the code with the extra quotes stripped out (and a semicolon thrown in)
String[] commands = new String[] {"soffice","-headless","-accept=socket,host=localhost,port=8100;urp;"};
Process process = Runtime.getRuntime().exec(commands);
int code = process.waitFor();
if(code == 0)
System.out.println("Commands executed successfully");
(Disclaimer: I don't know Java, and I haven't tested this!)
"/Applications/OpenOffice.org\ 2.4.app/Contents/MacOS/soffice.bin -headless -nofirststartwizard -accept='socket,host=localhost,port=8100;urp;StartOffice.Service'"
or simply escaping the quotes will work as well. We feed a command like this to an ant script that ultimately ends up in an exec call like you have above. I would also recommend restarting the process every 500 or so conversions because OOO does not properly free memory (depending on what version you are running).