I am trying to use ProcessBuilder in Java and I am not quite getting how to split up my arguments for it. For example, this command + arguments find . -name 'rc*'. Here below are few different argument splits and none of them are giving me the correct result. Any idea what I am doing wrong in the argument splitting?
//This is obvious error since I mixed arugments with the command
processBuilder.command("find . -name 'rc*'").directory(new File("/etc"))
//Gives me exit code 1 and no results
processBuilder.command("find", ". -name 'rc*'").directory(new File("/etc"))
//Gives me also exit code 1 and no results
processBuilder.command("find", ".", "-name", "'rc*'").directory(new File("/etc"))
//Gives me also exit code 1 and no results
processBuilder.command("find", ". -name", "'rc*'").directory(new File("/etc"))
//Gives me also exit code 1 and no results
processBuilder.command("find", ".", "-name 'rc*'").directory(new File("/etc"))
EDIT
When I tried to add .inheritIO(), and split all arguments, to this it worked partially that is I got printouts for files that have Permission denied.
processBuilder.command("find", ". -name 'rc*'").directory(new File("/etc")).inheritIO();
but as before it did not list my other "rc" files.
Listing all rc files in /etc directory:
//Here should be at least dozen files that print out when I use the command in terminal
Exit code: 1
find 'someFileName': Permission denied
find 'someFileName': Permission denied
find 'someFileName': Permission denied
My process and printout part
Process b;
b.processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(b.getInputStream()));
String line = "";
while((line = reader.readLine()) != null){
System.out.println(line);
}
SECOND EDIT
The thing is that if I change the ProcessBuilder command to a similar command (I guess) then it prints out the resulting files with no prob with the same code - i.e. I changed the command to ls -a like
processBuilder.command("ls","-a").directory(new File("/etc")).inheritIO();
//and then activate the process and print it just as before and all good ```
The launch is from Java so there is no need to escape the find parameter rc* with single quotes. A shell such as bash would expand rc* to actual files prefixed with "rc" in the current directory (and use wrong search value), but Java will not do that. Also every parameter must be in its own string:
processBuilder.command("find", ".", "-name", "rc*").directory(new File("/etc"));
or
processBuilder.command("find", "/etc", "-name", "rc*");
If find is reporting a lot of errors you may get problem that the process freezes because you don't read STDERR at same time as STDOUT. You can choose between running threads to consume streams, or redirecting STDERR->STDOUT, or send both or merged streams to a file with Process.redirectOutput(File) and Process.redirectError(File) before calling processBuilder.start(). Read this answer.
Related
Hello I am trying to execute following :
Process p = null;
StringBuffer rbCmd = new StringBuffer();
rbCmd.append("rsync -e \"ssh -i /root/.ssh/key\" -va --relative /home/lego/hyb/abc/PVR2/Testdata/./R887/SCM/System root#myMachine:/xyz/data/SCMdata/");
p = Runtime.getRuntime().exec(rbCmd.toString());
But I am getting following error on command line.Command executes correctly on command line
Missing trailing-" in remote-shell command.
rsync error: syntax or usage error (code 1) at main.c(361) [sender=3.0.6]
Issue is because of double quotes inside the command where I mention ssh key.
Please help with correction.
Your approach won't work because Runtime.exec() does not realize that "ssh -i /root/.ssh/key" is a single argument to rsync. Escaping the double-quotes keeps the compiler happy, but doesn't remove the fundamental problem, which is the limits of the built-in tokenizer.
You might have more luck with something like this:
Process p = Runtime.getRuntime().exec
(new String[]{"rsync", "-e", "ssh -i /root/.ssh/key", "-va" "--relative" ... });
That is, tokenize the command line yourself, and form the individual tokens into a String[]. You're deciding in advance what the arguments to rsync are, rather than allowing exec() to figure it out (wrongly).
Don't forget that if rsync produces any output, you'll need to arrange for your application to consume its stdout and stderr, or it could stall.
I working on a python 3 script for doing some bench (school purpose). So I need to invoke my JAR.
I use subprocess.check_output for that.
java_out = subprocess.check_output("java -jar my_jar.jar -p input_file", shell=True)
In terminal it works fine, I get the expected output and exit code is 0.
But in python, I get this :
Syntax error. (One of my java exception, but it might not happen in this case)
Traceback (most recent call last):
File "C:/Users/Jeremy/PycharmProjects/bench_bf/bench_script.py", line 41, in <module>
main()
File "C:/Users/Jeremy/PycharmProjects/bench_bf/bench_script.py", line 32, in main
result_list.append(bench(bf_file, stats_file))
File "C:/Users/Jeremy/PycharmProjects/bench_bf/bench_script.py", line 10, in bench
java_out = subprocess.check_output("java -jar my_jar.jar -p input_file", shell=True)
File "C:\Python34\lib\subprocess.py", line 620, in check_output
raise CalledProcessError(retcode, process.args, output=output)
subprocess.CalledProcessError: Command 'java -jar my_jar.jar -p input_file' returned non-zero exit status 5
Process finished with exit code 1
That does not make any sense to me. Can anyone help me ? Thanks !
The full code is following (I've also tried with absolute path) :)
import subprocess
import os
import re
FILE_NAME = "input_file"
JAR_NAME = "my_jar.jar"
TEST_ITER = 5
def bench(bf_file, stats_file):
java_out = subprocess.check_output("java -jar "+ JAR_NAME + " -p " + FILE_NAME, shell=True)
print(java_out)
m = re.search(".*EXEC_TIME : (\d*) ms.*EXEC_MOVE : (\d*)", java_out)
return [m.group(0), m.group(1)]
def init_stats(f):
f.write("Iterations; Exec time; exec move")
def write_file(f):
f.write("+++")
def main():
bf_file = open(FILE_NAME, "w", encoding="utf-8")
stats_file = open("bench-result.csv", "w")
write_file(bf_file)
init_stats(stats_file);
result_list = []
for i in range(0,TEST_ITER):
result_list.append(bench(bf_file, stats_file))
average_time = 0;
for res in result_list:
average_time += res[0]
average_time /= TEST_ITER;
stats_file.write(average_time + ";" + result_list[0][1])
main()
EDIT: I also tried java_out = subprocess.check_output(["java", "-jar", "my_jar.jar", "-p", "input_file"], shell=True), it changes nothing.
EDIT 2: Same result using absolute path or os.system
* SOLUTION *
Since I open the file in write mode, my JAR can't open it, and consider it's empty... Thanks my mate DjNikita :)
My first thought would be that there is something in your environment that is not transferring to the subprocess. Try this and see if it outputs anything that looks relevant
import os
for key in os.environ:
if any(token in key.lower() for token in ['java', 'jre', 'jdk']):
print(key, os.environ[key])
I've had another thought too. Some programs expect their input to be a tty (ie. interactive terminal) and get angry when they're fed in a pipe. Is there anything in your Java program that might cause it to expect a certain type of input stream?
Try specifying the absolute path of the jar file, as it might be that your sub-process isn't running the directory you think it is.
Try running 'dir' and seeing where it returns, for instance. Maybe check that 'java --V' (the version flag? not in a position to check at the moment) returns something indicating that Java ran, rather than an error. Basically, try and get a simple thing running via Python, then extend it.
When I tried to run Ansible with Runtime.getRuntime().exec with Java
Here is what I did:
String[] cmd = {"ansible-playbook", "/path/to/playbook", "--extra-vars", "'{\"filePath\":\"/path/to/file\"}'"};
Process process = Runtime.getRuntime().exec(cmd, null);
I got error message like this:
FAILED! => {"failed": true, "msg": "'filePath' is undefined"}
However when I executed the same command with terminal:
ansible-playbook /path/to/playbook --extra-vars '{"filePath":"/path/to/file"}'
Everything was fine...
I think there must be some differences between the command I ran in terminal and Java, maybe apostrophe or quotation mark ?
I'm wondering is there any way to get the real executed command of Runtime.getRuntime().exec? Just like I can get command line history of some user by history...
You are adding additional quotes in your third parameter:
"'{\"filePath\":\"/path/to/file\"}'"
If you do this, you're not executing the same command in your shell as you have above. You're actually executing (in bash):
ansible-playbook /path/to/playbook --extra-vars ''\''{"filePath":"/path/to/file"}'\'''
You don't need the single quotes around the value here: because you're passing these values directly, you don't have to worry about the quoting that you'd have to do in a shell. You can simply use:
"{\"filePath\":\"/path/to/file\"}"
I try to launch a batch file from my Java application, but I only get an error window. It says:
"1" could not be found. Make sure that you used the right name and
repeat the process
(Free translation from german Windows 10). "1" is the number I try to give to the batch file.
I try to launch from a directory which contains spaces, e.g.: C:\user\my stuff\ etc.
Here is the specific code I am using:
String[] commands = {"cmd", "/c" , "start", batchfile.toString() , String.valueOf(ParameterNumber)};
Process p = Runtime.getRuntime().exec(commands);
batchfile is a valid path written like this: C:\Users\Admin\directory and stuff\
ParameterNumber is a valid int between 1 and 100.
The first parameter of start is an application title (run start /? to see the minihelp). You may use an empty string.
However in this case start isn't necessary, simply remove it from commands.
I am running following unix command using ProcessBuilder and it is working fine.
String[] commands = {"egrep","search string","fileName"}
ProcessBuilder pb =...
Now I have an additional requirement to filter the output.
String [] commands = {"egrep","search string","fileName","|","awk\'$0 >\"time\" && $2==\"INFO\"\'"}
I am getting error "IO Exception: No such file error". It seems it is considering pipe(|) and other awk command as file.
I also tried adding prefix "bash -c" or "/bin/sh -c" like
String [] commands = {"bash","-c","egrep","search string","fileName","|","awk\'$0 >\"time\" && $2==\"INFO\"\'"}
Now I am getting error
"bash -c line0: syntax error near unexpected token 'is'bash:-c line0:"
I also tried giving entire egrep command in single string but it also didn't work.
Please advice what am I missing error to use pipe for filtering the output.
Without considering whether your proposed egrep/awk command line will work - I'm unsure it's what you intend - consider making the full command line a single argument to the -c option of bash, so you'll have only three strings involved in the construction of the ProcessBuilder. See SO question 3776195 for some more info.