Java executing Linux commands - java

I want to write a java code that executes some Linux command:
String cmd = "cd /home/arps/FBI" ;
Process p=Runtime.getRuntime().exec(cmd);
String [] arr = new String [9] ;
arr[0] = "cd /home/arps/FBI" ;
for(int n = 1 ; n < 9 ; n++){
String command = "mv" + " " + "/home/arps/FBI/hr" + n + ".txt" + " " + "/home/arps/FBI/hrs" + n +".txt" ;
arr[n] = command ;
}
Process pp=Runtime.getRuntime().exec(arr);
In above code: I try to rename 8 files named hr1, hr2 .... to hrs1 , hrs2 ... etc. In cd command I try to enter the required directory. However, I have used absolute path also. But the code is giving error:
java.io.IOException: Cannot run program "cd": java.io.IOException: error=2, No such file or directory
java.io.IOException: Cannot run program "mv /home/arps/FBI/hr1.txt /home/arps/FBI/hrs1.txt": java.io.IOException: error=2, No such file or directory
Can anybody help me why is this happening though I manually execute those command means "mv /home/arps/FBI/hr1.txt /home/arps/FBI/hrs1.txt" and executes properly?

cd is a built-in command to the current shell - you can't execute it - it's a shell built-in, as the cwd is a process-level setting, so a new process has it's own value. There is no way to change the cwd from within the java process.
The array argument version of exec is for executing a single command, where you have split the arguments yourself, not for executing multiple commands.
So you either need to give full paths, or implement the copy yourself in Java.

Change the final line of your program from
Process pp=Runtime.getRuntime().exec(arr);
to:
for (String cmdLine: arr) {
Process pp=Runtime.getRuntime().exec(cmdLine);
and you will execute each line separately, according to RunTime documentation.

You might be better off writing a shell script that does what you need and invoking that from Java.

arr array must store the arguments of command. Not seperated commands. refer to my question.
run shell command from java

If ls -l /home/arps/FBI/hrs1.txt outputs nothing as you said in the comments, then the file you're trying to rename simply does not exist, so the exception is right about this.
PS: IMHO this is not to be done in Java. Use scripting languages for such things. Way easier and way smaller code. For each problem, try to use the right tool, not one tool for all problems.

Related

Java command through CMD not working in C#.NET

I'm trying to run a java command in cmd using C# to get some inputs for my program, the path for Java is set correctly, and I am able to run Java commands in the cmd without any trouble but when I tried it in C#, it's showing " 'java' is not recognized as an internal or external command, operable program or batch file. " as if the path is not set.
But I am able to run the same command outside, don't know what seems to be the issue, kindly help, thanks in advance!
string cmd = #"/c java -jar """ + $"{treeEditDistanceDataFolder}libs" + $#"\RTED_v1.1.jar"" -f ""{f1}"" ""{f2}"" -c 1 1 1 -s heavy --switch -m";
Console.WriteLine(cmd);
var proc = new Process();
proc.StartInfo.FileName = "cmd.exe";
proc.StartInfo.Arguments = cmd;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.Start();
Console.WriteLine("Process started");
string output = proc.StandardOutput.ReadToEnd();
Console.WriteLine("Output was read");
string error = proc.StandardError.ReadToEnd();
proc.WaitForExit();
This line is your problem:
proc.StartInfo.UseShellExecute = false;
When UseShellExecute is true, the system and user PATH variables will be used if the application to launch is just the executable name. Because you're setting it to false, and java doesn't exist in your application's folder, it isn't possible for .NET to find it.
You have two options:
Set UseShellExecute to true so that it can use the PATH variable to find java.
Use a fully qualified path, e.g. "C:\Program Files\Java\jdk1.8.0_101\bin\java"
See this answer for more info.

Issue starting cmd.exe twice in a row

I am trying to automate some processes that were build in ancient times, for the sake of avoiding repetitive actions. It is required that the processes are started with one batch and stopped with another (this can not be changed btw).
So i made a commandline tool to do this (and many other repetitive stuff) and I have modelled a command that starts the 'startbatch' and a command that start the 'stopbatch'. Both commands work fine separatly (as I tested them separatly) but there seems to be a problem when i want execute them one after another (in the correct order ofcourse). I get the following error in new cmd.exe window:
The process cannot access the file because it is being used by another process.
the code that i am using to start the batches looks like this:
public void startBatchInDev(String company){
String startBatchFolder = locations.getLocationFor("startbatch");
try{
Runtime runtime = Runtime.getRuntime();
runtime.exec("cmd.exe /C cd \"" + startBatchFolder + "\" & start cmd.exe /k \"" + BATCHSTART + company.toLowerCase()+ "-dev" + BATCH_SUFFIX + "\"");
}
catch(IOException ioe){
ioe.printStackTrace();
}
}
public void stopBatchInDev(String company){
String startBatchFolder = locations.getLocationFor("startbatch");
try{
Runtime runtime = Runtime.getRuntime();
runtime.exec("cmd.exe /C cd \"" + startBatchFolder + "\" & start cmd.exe /k \"" + BATCHSTOP + company.toLowerCase()+ "-dev" + BATCH_SUFFIX + "\"");
}
catch(IOException ioe){
ioe.printStackTrace();
}
}
The names of the batchfiles are concatenated, but they are OK once the application is running.
The error message is quite clear, some file is locked and I can't access it because of it. Some googling confirms my suspicion, but I can't seem to find a solution for this. The hits in google are all about obvious uses of files, like an obvious shared resource. But in my case, i am not working on the same batch file. The stop and start batch are two different files. So I am actually starting to think that it might be the cmd.exe file that is being locked by windows...
So this question is actually two questions:
- what is the exact cause of the described problem?
- how do i programmatically fix this (if possible)?
thanks in advance!
So, basically, bat is not so great :-(
I was able to repro this from java, but I also found that this script:
#echo off
echo STOP
echo STOP >> E:\tmp\java\logfile.txt
C:\cygwin\bin\sleep.exe 1
echo STOP1 >> E:\tmp\java\logfile.txt
C:\cygwin\bin\sleep.exe 1
echo STOP2 >> E:\tmp\java\logfile.txt
When run twice like this:
start test.bat && start test.bat
Will fail with one or more messages like:
The process cannot access the file because it is being used by another process.
The reason is that " >> " redirection opens the file for Read/Write access but only FILE_SHARE_READ sharing. If two different programs attempt to open the file this way, one of them fails.
So, you cannot have two different batch files running at the same time and logging to the same file

commandline call from java

I'm looking to call the command line from a java program. I have successfully entered the command line using this bit of code
String[] cmd = new String[2];
cmd[0] = "cmd /c dir";
Runtime rt = Runtime.getRuntime();
System.out.println("Execing " + cmd[0]);
Process proc = rt.exec(cmd[0]);
However, the actual commands aren't working. I am not too familiar with command line, I have only ever typed directly into it. So my question is how do I pass multiple arguments in? For instance if I wanted to change to C:\ I would have thought I could just add cd\ on the end but this doesn't seem to work?
Thanks in advance
use the & symbol. Everything needs to go in at once. For instance: cd .. & echo "test" will go to the previous directory and then echo test.
Taken from here: http://forums.techguy.org/dos-other/697113-solved-multiple-commands-cmd.html

How can I invoke a Java program from Perl?

I'm new with Perl and I'm trying to do something and can't find the answer.
I created a Java project that contains a main class that gets several input parameters.
I want to wrap my Java with Perl: I want to create a Perl script that gets the input parameters, and then passes them to the Java program, and runs it.
For example:
If my main is called mymain, and I call it like this: mymain 3 4 hi (3, 4 and hi are the input parameters), I want to create a Perl program called myperl which when it is invoked as myperl 3 4 hi will pass the arguments to the Java program and run it.
How can I do that?
Running a Java program is just like running any other external program.
Your question has two parts :
How do I get the arguments from Perl to the Java program?
How do I run the program in Perl?
For (1) you can do something like
my $javaArgs = " -cp /path/to/classpath -Xmx256";
my $className = myJavaMainClass;
my $javaCmd = "java ". $javaArgs ." " . $className . " " . join(' ', #ARGV);
Notice the join() function - it will put all your arguments to the Perl program and separate them with space.
For (2) you can follow #AurA 's answer.
Using the system() function
my $ret = system("$javaCmd");
This will not capture (i.e. put in the variable $ret) the output of your command, just the return code, like 0 for success.
Using backticks
my $out = `$javaCmd`;
This will populate $out with the whole output of the Java program ( you may not want this ).
Using pipes
open(FILE, "-|", "$javaCmd");
my #out = <FILE>
This is more complicated but allows more operations on the output.
For more information on this see perldoc -f open.
$javaoutput = `java javaprogram`;
or
system "java javaprogram";
For a jar file
$javaoutput = `java -jar filename.jar`;
or
system "java -jar filename.jar";

Compiling a class using Java code using process

I have this piece of code that compiles a class called tspClassName, when I compile using this code:
Process compileProc = null;
try {
compileProc = Runtime.getRuntime().exec("javac -classpath ."
+ File.separator + "src" + File.separator
+ File.separator + "generated." + tspClassName + ".java -d ." + File.separator + "bin");
// catch exception
if (compileProc.exitValue() != 0)
{
System.out.println("Compile exit status: "
+ compileProc.exitValue());
System.err.println("Compile error:" +
compileProc.getErrorStream());
it outputs this:
"Compile exit status: 2
Compile error:java.io.FileInputStream#17182c1"
The class tspClassName.java compiles without errors otherwise, so I am guessing it has to do with the path,and in my eclipse project, the tspClassName.java resides in package homework4.generated inside src, is there something wrong with the path that I use in the code?
thanks
Your Java code runs a command that looks something like this:
javac -classpath ./src//generated.ClassName.java -d ./bin
I don't think that's what you want. I think you need to change your Java code so it maybe generates something like:
javac -classpath . src/generated/ClassName.java -d ./bin
^
Note the space after the classpath (".").
You can use the javax.tools.JavaCompiler or JCI that wrap this functionality.
I recommend doing something like this:
String command = String.format(
"javac -classpath . src%1$sgenerated%1$s%2$s.java -d .%1$sbin",
File.separator,
tspClassName
);
LOG("Executing " + command);
//... exec(command) etc
... where LOG is whatever your logging framework uses to log the command to be executed. This will help debugging immensely, since it was pointed out that the command you built is ill-constructed.
Alternately you can also build the string using replace
String command =
"javac -classpath . src/generated/ClassName.java -d ./bin"
.replace("/", File.separator)
.replace("ClassName", tspClassName);
This is perhaps more readable.
On draining Process streams
OP's comment suggests that waitFor() never returns. This is likely caused by compilation errors/warnings in javac process.
From the API:
Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.
You need to continuously drain the Process.getOutputStream() et.al.
See also
Java Puzzlers, Puzzle 82: Beer Blast
Related questions
Draining standard error in Java
I think the proper way to do this kind of work is programatically using the javax.tools API, not an external process:
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler()
Reference:
ToolProvider.getSystemJavaCompiler()
The problem could be with the file location instead of using single value parameter for exec()
try 3 parameter method which has the command, environment and location as parameters which helps us to move to the specified location and execute the command
check 6 and 8 methods for reference
http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html
Process compile = Runtime.getRuntime().exec("javac "+fname,null,new File(dir));
firstly you should use apache exec library if you want to use processes like that. Apache exec library makes things very easy.
Secondly you should print your std output and std error streams of your process which you are executing. Without them its no way to know whats being executed and what's it doing.
Thirdly, try to print the full cmd line which the process is executing. Copy that cmd line and try to run it manually. Most of the time you would find your issues this way.
And finally if your aim is just to compile a class / generate or modify a class file at runtime give this a good read and try. It has examples too. You could also try code generation / class manipulation libraries like BCEL, JavaAssist etc.
Best of luck.

Categories