Executing linux command from java using exec('command') method - java

I am trying to execute a Linux command from my java class using the method exec() from the Runtime class in this way:
public static String xxUtilInfoFile (String sPath , String sFileName) throws Exception
{
Runtime r = null;
Process p = null;
String line_value="";
String output_data="";
/*execute the process*/
r = Runtime.getRuntime();
p = r.exec("file -bi " + sPath + sFileName);
p.waitFor();
/*Return the standard error output*/
BufferedReader in=new BufferedReader(new InputStreamReader(p.getInputStream()));
output_data = in.readLine();
return output_data;
}
The Linux command I want to use is file -bi fileName and it runs well except in the case the fileName has blanks inside, and that is the point.
I've already tried to use double quotes and backslash (\) because this method runs in the Linux bash console, but it doesn't run if I pass it as an argument of exec method.
Could anyone help me to resolve this issue?

Perhaps, you should pass an array of Strings to the exec() method at line 9 of your code:
p = r.exec(new String[]{ "file", "-bi", sPath, sFileName});

Related

Open a file with its associated application and extra command line parameters

I would like to open a file with its associated application and a couple of command line parameters.
E.g. the_app.exe -someoption file.app, the_app.exe being the associated application for opening the .app files.
I was looking to the Desktop class with the hope to find either
a Desktop.getDesktop().open(file,options), or
a Desktop.getDesktop().getOpenFileHandler(file) and then build upon that with Process and ProcessBuilder
Neither do exist. Any other suggestion ?
In java you can use Runtime to run programs.
Runtime.getRuntime().exec("program");
You can also use "cmd" to run command-line commands.
Then, if option parameters weren't needed, you could simply use 'start' command.
//this will open notepad in my pc
Process pr = Runtime.getRuntime().exec("cmd /c start test.txt");
If you really need to pass commands you can use some auxiliar commands and build your own command-line:
With 'assoc' you retrieve the filetype
With 'ftype' you retrieve the application for a filetype
Then:
private static String command(Runtime rt, String command) throws IOException {
Process pr = rt.exec("cmd /c " + command);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(pr.getInputStream()))){
return reader.readLine();
}
}
public static void main(String[] args) throws IOException {
//without parameters is an easy job
Process pr = Runtime.getRuntime().exec("cmd /c start test.txt");
//with parameters things get messy
Runtime rt = Runtime.getRuntime();
String out1 = command(rt, "assoc .txt");
System.out.println(out1);
String assoc = out1.split("=")[1];
String out2 = command(rt, "ftype " + assoc);
System.out.println(out2);
String app = out2.split("=")[1].split(" ")[0]; //error prone, consider using regex
command(rt, app + " /P test.txt"); //This will print (/P) the file using notepad
}
Of course, none of these are portable at all.
For more info:
Running Command Line in Java
Best way to get file type association in Windows 10 from command line?
https://www.addictivetips.com/windows-tips/file-app-association-command-prompt-windows-10/
How to open file with default application in cmd?

Unable to send OS X terminal command via Java

I am trying to see if an iPhone is in tehtered mode on OS X and I am unable to send a terminal command using this code:
String [] cmdArray = new String[1];
cmdArray[0] = "/usr/sbin/networksetup -getinfo \"iPhone USB\"";
SendCommandForResponse(cmdArray);
...
static String SendCommandForResponse(String[] commandArray) throws IOException {
InputStream processOutput;
BufferedReader reader = null;
String line = " ", output = " ";
Runtime rt = Runtime.getRuntime();
Process p = rt.exec(commandArray);
processOutput = p.getInputStream();
reader = new BufferedReader(new InputStreamReader(processOutput));
while ((line = reader.readLine()) != null) {
System.out.println(line);
output += line + "\n";
}
return output;
}
When this code is ran, I receive this error:
IOException: java.io.IOException: Cannot run program
"/usr/sbin/networksetup -getinfo "iPhone USB"": error=2, No such file
or directory
I am able to run this command successfully through terminal manually but when ran inside NetBeans it gives an exception. What am I doing wrong? I am new to Java on OS X.
You should fill the command array like this:
String[] cmdArray = new String[3];
cmdArray[0] = "/usr/sbin/networksetup";
cmdArray[1] = "-getinfo";
cmdArray[2] = "iPhone USB";
Or in short:
String[] cmdArray = { "/usr/sbin/networksetup", "-getinfo", "iPhone USB" };
The first item should be only the command (the program to run)
The next items are the arguments
There is no need for extra quotes around an argument with a space in it.
When you run a command from Terminal directly, the shell interprets the command and separates it for you - which is why you need the quotes. But when you are running it from Java, the command is not handed to a shell and is not parsed. You have to do the separation of the command and the arguments yourself.

Running a grep command using java Runtime api

I need to grep some text inside a list of files(file count is huge) in unix server and then list the file name in a web gui. So I decided best way to achieve this is by writing a unix command executer using Runtime.getRuntime().
Works fine for most of the unix command but facing this strange grep issue.
First of all code:
public class UnixCommandExecutor {
private static StringBuffer output = new StringBuffer();
public static String exec(String command) throws Exception{
Process process = null;
process = Runtime.getRuntime().exec(command);
BufferedReader stdErr = getBufferedReader(process.getErrorStream());
BufferedReader stdIn = getBufferedReader(process.getInputStream());
StringBuffer data = extractData(stdErr);
if (data.length() >= 1) {
System.out.println("Error: " +data.toString());
throw new Exception(data.toString());
}
data = extractData(stdIn);
if (data.length() >= 1) {
output = data;
System.out.println("Output: " +data.toString());
}
return output.toString();
}
private static BufferedReader getBufferedReader(InputStream stream) {
InputStreamReader inReader = new InputStreamReader(stream);
BufferedReader buffReader = new BufferedReader(inReader);
return buffReader;
}
private static StringBuffer extractData(BufferedReader reader)
throws IOException {
StringBuffer data = new StringBuffer();
String s = "";
while ((s = reader.readLine()) != null) {
data.append(s + "\n");
}
return data;
}
public StringBuffer getOutput() {
return output;
}
}
Now the call would be something like this:
String output = exec("find . -name blah");
This works fine and the result is perfect. Or any other unix command executes and provides the result properly.
But when grep command is used it gives a strange error:
String output = exec("grep -l executor *");
Error: grep: *: No such file or directory
This is strange, since if I run this command directly on unix it gives the desired result.
Also tried giving the file path something like,
String output = exec("grep -l executor /file/path/*");
even then the error is:
Error: grep: /file/path/*: No such file or directory
Any ideas? or any other better way to solve this?
Any suggestion is welcome.
The * is interpreted by the shell, not grep itself. So it doesn't work if you start grep from your Java program.
You can use grep with -r to make it search recursively, then use . for the current directory:
grep -lr executor .
To simulate the behaviour of the shell, just replace * with a space separated list of all files in the folder you want to search in. You can get the list of all files with:
StringBuilder str = new StringBuilder();
for (File f : new File("your folder").listFiles()) {
if (f.isFile()) {
str.append(' ').append(f.getPath());
}
}
Now just replace the * with the result of str.toString().

How to get short-filenames in Windows using Java?

How to get the short-filename for a long-filename in Windows using Java?
I need to determine the short-filenames of files, stored on a Windows system, using Java(tm).
Self Answer
There are related questions with related answers. I post this solution, however, because it uses Java(tm) code without the need for external libraries. Additional solutions for different versions of Java and/or Microsoft(R) Windows(tm) are welcome.
Main Concept
Main concept lies in calling CMD from Java(tm) by means of the runtime class:
cmd /c for %I in ("[long file name]") do #echo %~fsI
Solution
Tested on Java SE 7 running on Windows 7 system
(Code has been reduced for brevity).
public static String getMSDOSName(String fileName)
throws IOException, InterruptedException {
String path = getAbsolutePath(fileName);
// changed "+ fileName.toUpperCase() +" to "path"
Process process =
Runtime.getRuntime().exec(
"cmd /c for %I in (\"" + path + "\") do #echo %~fsI");
process.waitFor();
byte[] data = new byte[65536];
int size = process.getInputStream().read(data);
if (size <= 0)
return null;
return new String(data, 0, size).replaceAll("\\r\\n", "");
}
public static String getAbsolutePath(String fileName)
throws IOException {
File file = new File(fileName);
String path = file.getAbsolutePath();
if (file.exists() == false)
file = new File(path);
path = file.getCanonicalPath();
if (file.isDirectory() && (path.endsWith(File.separator) == false))
path += File.separator;
return path;
}
I found a slight problem Osmund's solution. It doesn't work properly for this file name for some reason:
N:\directoryY\tmp\temp\asdfasdf sdf dsfasdf [dfadss]\[asdfas] asdfasd asd asdfasdf ~fdfsdfdfdsfdfdfdfdfd~ TTTm7-9 [RR 1234a5678 A.888 OKOK]a
I'm not really sure why exactly. But if you run the command a slightly different way (using ProcessBuilder), it works. Here is the new code (I am using BufferedReader to read the output, it is much cleaner).
public static String getMSDOSName(String path) throws IOException, InterruptedException {
Process process = new ProcessBuilder().command("cmd", "/c", "for %I in (\"" + path + "\") do #echo %~fsI").start();
process.waitFor();
try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
return br.readLine();
}
}
This is the output of the original solution vs my solution. The original solution fails to shorten the last path element:
N:\DIRECT~1\tmp\temp\ASDFAS~1\[asdfas] asdfasd asd asdfasdf ~fdfsdfdfdsfdfdfdfdfd~ TTTm7-9 [RR 1234a5678 A.888 OKOK]a
N:\DIRECT~1\tmp\temp\ASDFAS~1\_ASDFA~1.888

Opening exe with parameters in Java, don't understand parameters

I'm aware how to open an exe program with parameters in Java from finding the answer online. However my specific shortcut is a bit complicated for me to understand.
I'm trying to open a shortcut which has the following target:
C:\Windows\System32\javaw.exe -cp jts.jar;total.2012.jar -Dsun.java2d.noddraw=true -Dswing.boldMetal=false -Dsun.locale.formatasdefault=true -Xmx768M -XX:MaxPermSize=128M jclient/LoginFrame C:\Jts
In my program I've split up the location and what I think are the parameters. However when I run the program I get the error 'Could not create Java Virtual Machine, Program will Exit'. Can someone with a better understanding of whats going on explain what I might be doing wrong or point me in a direction where I can read up?
String location = "C:\\Windows\\System32\\javaw.exe";
String p1="-cp jts.jar;total.2012.jar";
String p2="-Dsun.java2d.noddraw=true";
String p3="-Dswing.boldMetal=false";
String p4="-Dsun.locale.formatasdefault=true";
String p5="-Xmx768M";
String p6="-XX:MaxPermSize=128M";
String p7="jclient/LoginFrame" ;
String p8 = "C:\\Jts";
try {
Process p = new ProcessBuilder(location,p1,p2,p3,p4,p5,p6,p7,p8).start();
} catch (IOException ex) {
Logger.getLogger(Openprogramtest.class.getName()).log(Level.SEVERE, null, ex);
}
Each String you pass to ProcessBuilder is a separate argument (except the first one, which is the command).
Think of it like the args[] which are passed to your main method. Each String would be a separate element in the array.
I suspect that p1 is been interpreted as a single argument, when it should actually be two...
Try separating this argument into two separate parameters
String location = "C:\\Windows\\System32\\javaw.exe";
String p1="-cp";
String p2="jts.jar;total.2012.jar";
String p3="-Dsun.java2d.noddraw=true";
String p4="-Dswing.boldMetal=false";
String p5="-Dsun.locale.formatasdefault=true";
String p6="-Xmx768M";
String p7="-XX:MaxPermSize=128M";
String p8="jclient/LoginFrame" ;
String p9 = "C:\\Jts";
Amendment
Look at the -cp parameter, it appears that the class path elements are relative to the location that the command is executed. This suggests that you need to use the ProcessBuilder#directory(File) to specify the location that the command should executed from.
For example, if you program is installed in C:\Program Files\MyAwesomeApp, but you run it from the context of C:\Desktop, then Java won't be able to find the Jar files it needs, generally raising a ClassNotFound exception.
Instead, you need to tell ProcessBuilder that you want the command to executed from within the C:\Program Files\MyAwesomeApp context.
For example...
ProcessBuilder pb = new ProcessBuilder(...);
pb.directory(new File("C:\Program Files\MyAwesomeApp"));
// Other settings...
Process p = pb.start();
Updated from running example
Just to make the point. I built myself a little Java program that simple printed a simple message to the standard out.
When I run this, it works as expected...
try {
String params[] = new String[]{
"C:\\Windows\\System32\\javaw.exe",
"-cp",
"C:\\...\\TestSimpleProcessBuilder\\build\\classes",
"-Dsun.java2d.noddraw=true",
"-Dswing.boldMetal=false",
"-Dsun.locale.formatasdefault=true",
"-Xmx768M",
"-XX:MaxPermSize=128M",
"testsimpleprocessbuilder/HelloWorld",
"Boo"
};
ProcessBuilder pb = new ProcessBuilder(params);
pb.redirectErrorStream();
Process p = pb.start();
InputStream is = p.getInputStream();
int in = -1;
while ((in = is.read()) != -1) {
System.out.print((char) in);
}
is = p.getErrorStream();
in = -1;
while ((in = is.read()) != -1) {
System.out.print((char) in);
}
System.out.println("p exited with " + p.exitValue());
} catch (IOException ex) {
Logger.getLogger(TestSimpleProcessBuilder.class.getName()).log(Level.SEVERE, null, ex);
}
When I change the arguments from
"-cp",
"C:\\...\\TestSimpleProcessBuilder\\build\\classes",
to
"-cp C:\\...\\TestSimpleProcessBuilder\\build\\classes",
It fails with...
And outputs
Unrecognized option: -cp
C:\DevWork\personal\java\projects\wip\StackOverflow\TestSimpleProcessBuilder\build\classes
And if you're wondering, this is the little test program I wrote that gets run...
package testsimpleprocessbuilder;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello world - world says " + (args.length > 0 ? args[0] : "Nothing"));
}
}

Categories