Runtime.getRuntime().exec() doesn't execute some commands - java

I'm beginner at java and have some problems. I've read several topics about this theme but none of them worked for me. Here is my code:
try
{
Console console = System.console();
String command;
while(true)
{
command = console.readLine("Enter input:");
Process proc = Runtime.getRuntime().exec(command);
// Read the output
BufferedReader reader =
new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = "";
while((line = reader.readLine()) != null) {
System.out.print(line + "\n");
}
proc.waitFor();
}
}
catch(Exception e) {}
So what I'm trying is to make a java program and run terminal commands in it(I'm using linux). This program works with commands like "ls" "ps ef" and others but it doesn't work when I type "cd". I know that cd makes different process and should be used this way: "Runtime.exec(String command, String[] envp, File dir)". My questions is:
How to make my program run all kinds of terminal commands? Sorry if question sound silly. Thank you.

The cd command is a shell built-in command. There is no shell when you run a command via exec(...). Indeed, if you try to find a cd command in any of your system's bin directories, you won't find one ... because it is impossible to implement as a regular command.
If you are trying to use cd to change the current directory for the JVM itself, that won't work because a command can only change the current directory of itself and (after that) commands that it launches itself. It can't change its parent processes current directory.
If you are trying to use cd to change the current directory for subsequent commands, that won't work either. The context in which you set the current directory ends when the command finishes.
In fact, the right way to change the directory for a command run using exec is to set it via the ProcessBuilder API itself.
How to make my program run all kinds of terminal commands?
You can't. Some of the "terminal commands" only make sense as shell commands, and that means you need a shell.
I suppose, you could consider emulating the required behaviour in your Java code. That would work for cd ... but other commands are likely to be more difficult to cope with.
(For what it is worth, it is possible to implement a POSIX compatible shell in Java. It is just a LOT of work.)

you've actually got to run the console you want to use (ie sh, csh, bash, etc) and then use the process OutputStream to feed in commands

I think the Problem is not your Code, the command is the problem...
what do you want to see if your command is cd ??
In Background it changes the path but you get nothing back.
Changing the Directory is not processing any output.

This worked for me:
Runtime.getRuntime().exec(new String[]{ "/system/bin/sh", "-c", "ls -l" } );

Related

Check if jar is running or not

I would like to check whether a jar of mine is running on the users system, to then relaunch if it is closed.
I am aware of the command jps -l which makes it possible to check the current running jars. Only problem is that for that line to work, it requires the user to have a JDK installed. So I was then wondering whether or not there is an equivalent to the jps -l line, which doesn't need a JDK or anything, but just checks whether a specific jar is running.
In the past I have also used the line cmd /c tasklist for Windows and the line top -F -R -o cpu for Mac. To check whether an app or exe was running, but that doesn't really seem to be working. When running the tasklist line on Windows and I then check for an exe called "myApp", it doesn't find it. Even though it might be running. Otherwise this would have been a perfect method, to check for a running app, exe or jar.
Here is an example code of how I tried to use the tasklist command to check for a specific executable.
try {
String procss;
Process pRun = Runtime.getRuntime().exec("cmd /c tasklist");
BufferedReader input = new BufferedReader(new InputStreamReader(pRun.getInputStream()));
while ((procss = input.readLine()) != null) {
if(!procss.contains("myApp"))
{
//Runtime command to launch exe or app.
}
}
input.close();
} catch (Exception err) {
err.printStackTrace();
}
Basically I would like to just edit the code above, to have a command line, of which is able to actually check whether the exe, app or jar is running. Maybe there is an alternative to cmd /c tasklist and top -F -R -o cpu, which is able to get all processes running on a pc and not just .exe or .app
On windows, you could use the wmic command to get the command line parameters a program was launched with.
For example, using wmic process where "name like '%java%'" get commandline,processid (basically just means "get the PID and command line arguments of process with a name like java") gives me this output for a test program:
616
"C:\Program Files\Java\jre1.8.0_111\bin\javaw.exe" -jar "A:\Programmering\Java\Pong\out\artifacts\Pong_jar\Pong.jar"
As you can see, you can get the location of the jar file which is running (which you could then use to check if it's your program). In this case, I just launched it by double clicking the jar file, you may get different outputs if you launch it in a different way, but there should always be something you can use to identify the java process (like a main class or jar file).

Executing a .exe or .linux file in Java during Run time

I am trying to create a function within a Java Class that can execute a .exe or a .linux file during runtime.
The program is espresso.exe (for Windows OS) and espresso.linux for (Linux based systems)
Typically, the way to run the program is by going to command line, and going to the folder in which the executable is stored and typing:
(in Command Prompt)
espresso A0.txt > m.txt
or espresso A0.txt (which returns the output in cmd)
(in linux Terminal)
./espresso.linux A0.txt > m.txt
or ./espresso.linux A0.txt (which returns the output in the terminal window)
Here A0.txt is the input argument and m.txt is the file that espresso creates.
I have stored A0.txt and espresso.linux and espresso.exe under a folder src/resources
I tried the following:
ProcessBuilder pb = new ProcessBuilder("./src/resources/espresso.exe","src/resources/A0.txt",">src/resources/m.txt");
try {
Process p = pb.start();
}catch (IOException ex) {
Logger.getLogger(NetSynth.class.getName()).log(Level.SEVERE, null, ex);
}
I also tried:
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("src/resources/espresso.linux src/resources/A0.txt > src/resources/m.txt");
int waitFor = p.waitFor();
Both of them fail to identify the file to be executed and do not run the command. I understand there may be many errors in the 2 approaches. I could use some help to figure out the approach and the code to be written to run the executable file.
Also, is there a path to be mentioned to run espresso.linux? Will /src/resources/espresso.linux suffice?
Thanks in advance.
You can't do standard output redirection like this (because the ">" sign is interpreted by the OS shell), see this answer for a working solution: ProcessBuilder redirecting output
Since Java 7 there is a Java-only solution in order to achieve redirecting: http://tamanmohamed.blogspot.co.at/2012/06/jdk7-processbuilder-and-how-redirecting.html
The > is a shell syntax. If you want to redirect the output to a file you need to use a shell or read the output and write it to a file yourself.
The way you have used > it is just another argument.

Ruby script that sets environment variable fails with Invalid argument - ruby_setenv (Errno::EINVAL) when started from a Java process on Windows

I have a very simple ruby script that looks like this:
puts "Running test program"
ENV["TEST"] = "foo"
puts ENV["TEST"]
When I run this script from the command line it works as expected:
C:\Temp\rb-test>ruby foo.rb
Running test program
foo
What I need to do is to launch this script from a Java program. The Java program looks like this:
Path path = FileSystems.getDefault().getPath("c:", "temp", "rb-test");
ProcessBuilder pb = new ProcessBuilder("ruby.exe", "foo.rb").directory(path.toFile()).redirectErrorStream(true);
Process process = pb.start();
process.waitFor();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = bufferedReader.readLine();
while (line != null) {
System.out.println(line);
line = bufferedReader.readLine();
}
When I run the Java program from Eclipse I get the following output:
foo.rb:2:in `[]=': Invalid argument - ruby_setenv (Errno::EINVAL)
from foo.rb:2:in `<main>'
Running test program
In reality I am calling a larger Ruby script from a third party product (Vagrant), why changing the Ruby script is not an option.
Why is this happening? Can I get around it by modifying my Java code somehow?
Ruby version: ruby 1.9.3p0 (2011-10-30) [i386-mingw32]
Update: The java code actually works if I run it from a cmd window. It does not work when I run it from within Eclipse. Unfortunately this does not help much since I am working on a tool we will run from within Eclipse.
Update 2: If I start a cmd window from Eclipse, I get the same problem when I run the ruby script from within this cmd window. This leads me to believe there is some kind of permission issue. However, I cannot see any permission differences between the cmd I start through the start menu and the one started through Eclipse. Both are run as the same user and all security properties I can see for the process are identical.
Update 3: Tried the latest version of Ruby (2.0.0p247 (2013-06-27) [i386-mingw32]). Same behavior.
The problem was that when I started the Ruby script from Eclipse I had a different environment. Specifically, I had a CLASSPATH environment variable that looked really strange. I think the cause of this is the size of the CLASSPATH variable. It is really really long before being passed on to my sub process but within the sub process it is truncated and looks broken.
I am suspecting I am running into problems with the max size of the Windows environment block (see details here: http://blogs.msdn.com/b/oldnewthing/archive/2010/02/03/9957320.aspx). I will not investigate this further but have fixed my code to remove the CLASSPATH variable before starting the process.
Path path = FileSystems.getDefault().getPath("c:", "temp", "rb-test");
ProcessBuilder pb = new ProcessBuilder("ruby.exe","foo.rb").directory(path.toFile()).redirectErrorStream(true);
pb.environment().remove("CLASSPATH");
Process process = pb.start();
process.waitFor();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = bufferedReader.readLine();
while (line != null) {
System.out.println(line);
line = bufferedReader.readLine();
}
Had a similar issue running vagrant as part of this Wocker installation:
http://wckr.github.io/
The problem was my system environment PATH was too long. I trimmed out a load of cruft from it and vagrant (based on ruby) runs up fine.

Running Shell script on server

I have an Stand alone Application which runs Shell Script(with parameters)in Ubuntu.
ProcessBuilder pb1 = new ProcessBuilder("sh","deltapackage_app.sh","part_value","pathtofile");
Process process1 = pb1.start();
I am taking parameter through GUI.
Now same thing i want to implement in web application where i can take inputs form web page and send it to server and then server will execute the shell script with parameters.
Can any one suggest me the best way of doing this. What things should i use to do this.
I Know i have to learn many things about server. Or can i use same code with Browser based Application.
Consider the following line of code:
Process p = Runtime.getRuntime().exec("/bin/sh -c /bin/ls > ls.out");
This is intended to execute a Bourne shell and have the shell execute
the ls command, redirecting the output of ls to the file ls.out. The
reason for using /bin/sh is to get around the problem of having stdout
redirected by the Java internals. Unfortunately, if you try this
nothing will happen. When this command string is passed to the exec()
method it will be broken into an array of Strings with the elements
being "/bin/sh", "-c", "/bin/ls", ">", and "ls.out". This will fail,
as sh expects only a single argument to the "-c" switch. To make this
work try:
String[] cmd = {"/bin/sh", "-c", "/bin/ls > out.dat"};
Process p = Runtime.getRuntime().exec(cmd);
Since the command line is already a series of Strings, the strings
will simply be loaded into the command array by the exec() method and
passed to the new process as is. Thus the shell will see a "-c" and
the command "/bin/ls > ls.out" and execute correctly.
http://www.ensta-paristech.fr/~diam/java/online/io/javazine.html

Running a script from Java

I have a number of scripts that I run on Windows through cygwin.
These script files always require manual editing whenever I take a new sandbox.
Thus, I was thinking of writing a little Java UI app that will edit the scripts automatically based on a users UI settings.
I've read a few other posts regarding running a script file from Java but didn't see any on how to run them on Windows through cygwin.
Has anyone else done this or know of a previous post that they could refer me to?
If cygwin is on your path, you can execute it like any other external program from Java.
Note: You have to read the streams from parallel threads in real code! This is just a proof of concept for running a bash script through cygwin on windows!
Process process = Runtime.getRuntime().exec("bash -c ./script.sh");
InputStream inputStream = process.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
If you execute the Cygwin.bat file found in the Cygwin install directory you will see your session turns into a Cygwin session and you can then run all the commands you can in a cygwin session.
If you then add the cygwin/bin directory to your path, you can execute commands directly like a linux environment.
In my case I added the following to the end of my PATH system variable C:\cygwin64\bin, and I can now run bash and other commands directly like a normal session.

Categories

Resources