Java IOException on exec call with any command-line arguments - java

I've got a java application that will eventually get fairly deep into external process integration, including IPC with those processes. For now though, what I'm trying to do is simply run a powershell script from java.
what I've got:
private void runPowershellScript() {
String command =
"" + "powershell" + " ";
// Paths.get("").toAbsolutePath() + "\\" + scriptFileName + " " +
// Paths.get("").toAbsolutePath() + "\\" + INPUT_FILE_NAME + " " +
// Paths.get("").toAbsolutePath() + "\\" + OUTPUT_FILE_NAME + "";
try {
ProcessBuilder builder = new ProcessBuilder(command);
builder.redirectErrorStream(true);
Process process = builder.start();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
With what you see there, I get the Windows Powershell name and copyright coming out over that reader, but if I add any of the commented out lines (all of which resolve to proper paths, eg C:\Users\Geoff\Code\OPTIP\FakeProgram.ps1) I get:
java.io.IOException: Cannot run program "powershell C:\Users\Geoff\Code\OPTIP\FakeProgram.ps1 ": CreateProcess error=2, The system cannot find the file specified
I've tried a dozen different combinations of strong and weak quotes, and I've tried passing them as arguments to cmd.exe /c powershell ... but nothing I've tried runs the script. If there is a single space in the command string, I get an IO Exception.
I'm wondering if maybe it has something to do with character encoding? When I simply invoke powershell, I'm getting 'back from reader.readLine() is:
W\u0000i\u0000n\u0000 ... Which I presume is my IDE's (IntelliJ's) way of telling me its "Windows Powershell" with a null unicode character between each letter.
The Java ProcessBuilder documentation is a little vague on exactly what you can pass as arguments:
a command, a list of strings which signifies the external program file to be invoked and its arguments, if any. Which string lists represent a valid operating system command is system-dependent. For example, it is common for each conceptual argument to be an element in this list, but there are operating systems where programs are expected to tokenize command line strings themselves - on such a system a Java implementation might require commands to contain exactly two elements.
I dont know what that means. The command I'm trying to give it works from a CMD and Powershell window, and also from the windows run dialog.
gist containing the class of above method:
https://gist.github.com/Groostav/9c5913e6f4696a25430d
gist containing my powershell script:
https://gist.github.com/Groostav/347a283ac7ec6a738191
Thanks for any help.

You have to put the arguments in separate strings, not concatenating them to the powershell call as a single string.
Something like
new ProcessBuilder("Powershell", scriptFileName, INPUT_FILE_NAME);

Related

Linux: Running Transmission through Java Runtime.exec() gives error

I have a bit of a weird situation. I'm writing a Java program to communicate automatically with Transmission on my Raspberry Pi (Linux).
I have the following code (simplified and edited for convenience/security):
String s;
String fullCommand = "transmission-remote -n username:password -a /location/to/file.torrent";
String[] cmd = fullCommand.split(" ");
Process p = Runtime.getRuntime().exec(cmd);
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((s = br.readLine()) != null) {
System.out.println("line: " + s);
}
p.waitFor();
System.out.println("exit: " + p.exitValue());
p.destroy();
The output I get is "non-existing or invalid torrent file".
If I run the exact same script on the command line, I get success (so the file exists and is valid).
I've read that Runtime.exec() has problems with spaces. Hence the split(" ").
It does not work without it either.
I know Runtime.exec() isn't the same as command line, but is there any way I could get this working?
I have a workaround, but I'd like to do it in one step.
If anyone is interested: the workaround is writing the command to a .sh file, make it executable and run that using Runtime.exec(). This does work.

Problems with running command line from Java

I've been trying to run a compiled C program from Java using following commnand. Then I want to get results from process' input stream.
Process p = Runtime.getRuntime().exec(commandLine);
Now, my command is this (first string is path to program, second and third are paths to files, which program takes as params):
trec_eval.8.1\trec_eval.exe trec_eval.8.1\czech TREC\results_2016-04-26_20_52_175.txt
When I run it normally from command line (I'm on Windows 10), it works as expected (C program finishes without errors and prints expected output into the command line), but alas, when I run it from Java, it doesn't work. Both stdout and stderr streams of the process are empty and process' exit status is some error code.
Here is minimal "working" example (I omitted stderr stream, since it made this code snippet too long):
String commandLine = "trec_eval.8.1\\trec_eval.exe" +
" trec_eval.8.1\\czech + " " + file;
System.out.println("Command: " + commandLine);
Process process = Runtime.getRuntime().exec(commandLine);
BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder output = new StringBuilder("Output:\n");
for (String line; (line = stdout.readLine()) != null; ) {
output.append(line).append("\n");
}
System.out.println(output.toString());
int exitStatus = 0;
try {
exitStatus = process.waitFor();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
System.out.println("Exit status: " + exitStatus);
stdout.close();
Output from this code are following lines:
Command: trec_eval.8.1\trec_eval.exe trec_eval.8.1\czech TREC\results_2016-04-27_18_27_585.txt
Output:
Exit status: -1073741515
Obviously, I have read several other answers here on Stackoverflow and elsewhere. Unfortunately, code in said answers was pretty much the same as mine (and did not work for me in the same way as my code does not work).
Can someone please tell me, what am I doing wrong? Why is stdout stream empty instead of containing C program's output? Why does not the process exit with status 0 (as it should), but with before-mentioned monstrosity? Finally, if you know, why my Java code does not work as expected, can you explain, why the exact same command works from the the command line?
Thanks in advance.
It seems like the program is not getting something it needs in it's environment. You said the program exited with an error code--so that sounds like your Java code is doing exactly what it should be doing (Starting the program and reading the exit code).
Your paths look relative--perhaps Java isn't starting in the directory you think it is? Try doing a full path to your argument and see if that helps.
Is there a way you can interpret the error code from the app?
If all else fails, try running it through a shell (either cmd /c or sh depending on your OS) using full paths. You can test that without java, then pass the whole thing to java and see if you get the same results.

Get Windows Command Line charset in java

I've been having problems reading output of windows command line from Java, i'm using Runtime.getRuntime().exec()
I simplified my test case: I have a file called お読みください.txt, and i execute the following command cmd /c dir C:/PATH
Note: The actual command is tasklist, but it's the same result as long as i use Runtime.getRuntime().exec()
String[] cmd = new String[]{ "cmd", "/c", "dir" };
Process process = Runtime.getRuntime().exec(cmd);
BufferedReader stdInput =
new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
String s, result = "";
while ((s = stdInput.readLine()) != null) {
if (!s.isEmpty()) {
result += s + "\n";
}
}
System.out.println(result);
I just get ���ǂ݂�������.txt
I tried with no charset, default, and the other ones; after testing all charsets, i got the one i was looking for: Shift_JIS
And that must be because i have set Language for non-Unicode applications as Japanese. systeminfo.exe says ja;Japanese for Regional Config.
I can simply use Shift_JIS to read, but it will only work in my computer. What about other system configurations?
The question is, how can i get the correct charset to read Windows Console output?
Base on the answer of What encoding/code page is cmd.exe using?
You can execute cmd /k chcp && pause && exit to get current code page. Using Code Page Identifiers to find the mapping Java encoding name.

Runtime.exec() to bash javac error

I'm using Runtime.exec() to run a shell script in a Java program.
The script basically compiles a java program and runs it and goes something like:
./run2.sh "/Users/user/Desktop/Test.java" "Test" "/Users/user/Desktop/"
my parameters in general are the absolute path of the java file, class name and directory where the supposedly compiled class file is
my script is simply
javac "$1"
cd "$3"
java "$2"
I've tried running the resulting command in my Terminal and it works fine. however when the java program runs it, I get and error:
javac: invalid flag: "/Users/user/Desktop/Test.java"
What should I do? I've tried every possible script I can find on the internet (*edit: and I can think of, of course)
(*edit: execute statement)
// some code here...
String[] outFile = translate.translate();
try {
String params = "";
for(String sss: outFile) {
String tmp = "\"" + sss + "\"";
params += tmp + " ";
}
String command = "./run2.sh "+params;
System.out.println(command);
Process proc = Runtime.getRuntime().exec(command);
} //respective catch
the first line, String[] outFile = translate.translate() returns an array Strings of my supposedly parameters
Your mistake is including quote characters in the command string that you are passing to exec(). The exec() method does NOT know how to deal with quotes or other "shell language" stuff. You would be better off trying to execute the command something like this:
Runtime.getRuntime().exec(new String[]{command, arg1, arg2, arg3});
where the command and arguments strings DO NOT have quotes around them.

Unable to execute my command after SSH in remote server

I have written a code that does SSH in servers and runs a Java file with arguments.
The problem I am facing is that the code successfully does SSH in but it does not run the command after that. Strangely If I run the command from the server alone it works. Any suggestions on this please?
Following is the code:
public void getSSH(String code, String newCode, JspWriter out){
try{
File f = new File("/usr/site/html/Output.txt");
BufferedWriter output = new BufferedWriter(new FileWriter(f));
String Servers[] = {"root#web233.xyz.com","root#web234.xyz.com","root#web235.xyz.com","root#web153.xyz.com"};
for(int i =0;i<Servers.length && i<1 ;i++){
Process p = Runtime.getRuntime().exec("/usr/site/swapimages.sh "+Servers[i]+" '/root/testRemote.sh "+ code+" "+ newCode+"'");
out.println("/usr/site/swapimages.sh "+Servers[i]+" '/root/testRemote.sh "+ code+" "+ newCode+"'"+"<br>");
Utils.waitFor(10000);
}
}
}
I have also been recommended JSch but haven't looked into it yet.
The reason it isn't working is that the quotes in this version don't have the same effect as they do on the command line. When you call SSH from bash, you put the remote command in quotes so that it is all interpreted as a single argument. Bash does the separation of the arguments for you. With exec, Java is splitting up the arguments for you. The documentation for exec describes how it separates. It uses a StringTokenizer, which is fairly dumb and seperates the line based on spaces (ignoring the quotes). This means that the array of arguments passed into the command is something like:
{ "/usr/site/swapimages.sh", "root#something", "'/root/testRemote.sh",
code, newCodeContents + "'" }
It could be even more strings if code or newCode have spaces in them. Notice that your command is multiple elements in the array and will therefore be treated as multiple arguments by ssh. In addition, ssh will actually try to execute a command that is in a directory that is named '. What you want to pass in, though, is:
{ "/usr/site/swapimages.sh", "root#something",
"/root/testRemote.sh " + codeContents + " " + newCodeContents }
Notice that there are no quotes and the whole command is the third element in the array.
So, you just need to manually create the string array and use the other form of exec that takes a string array and that should fix the problem.

Categories