I'm trying to get the output of grep linux shell command in java by using process builder. But i got a stuck in this case. Please help me.
Thank in advice!
String[] args = new String[7];
args[0] = "/bin/bash";
args[1] = "-c";
args[2] = "grep";
args[3] = "-n";
args[4] = "-e";
args[5] = "KERNELVERSION";
args[6] = kernelFilePath.trim();
ProcessBuilder pb;
Process process = null;
try {
pb = new ProcessBuilder(args);
pb = pb.directory(new File(directory));
pb.inheritIO();
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
process = pb.start();
process.waitFor();
} catch (IOException | InterruptedException e) {
System.out.println("executeCmdWithOutput() exception : " + e.toString());
} finally {
if (process != null) {
process.destroy();
}
}
==> Error:
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.
I tried the command in bash and it worked fine:
grep -n -e KERNELVERSION ..../Makefile
Have you tried change the args[2] as full command?
Also, you can use pgrep, it does not require you to use pipe.
You don't need to explicitly run /bin/bash in order to execute the grep process. Just call it directly and ProcessBuilder will run it:
String[] args = {"grep", "-n", "KERNELVERSION", kernelFilePath.trim()};
Also, you don't need to use the -e option, unless there are multiple patterns that you are searching for.
If you really wanted to run grep in /bin/bash:
String[] args = {"/bin/bash", "-c", "grep -n KERNELVERSION " + kernelFilePath.trim()};
passes a single argument to bash containing the full command and arguments to execute.
Related
I have seen similiar questions on this site, but none of them seem to address/solve my problem, so I figured there is something specifically wrong with my program. I am trying to execute a very simple command, which is to take a string of a process name from a textfield input and concatenate it to a command to return and print the title of the window. This is my code:
String line;
Process p = null;
try
{
String command = "tasklist /v /fo list /fi \"imagename eq " + tf.getText().trim() + "*\"| find /i \"window title:\"\n";
p = Runtime.getRuntime().exec(command);
BufferedReader input =
new BufferedReader(new InputStreamReader(p.getInputStream()));
System.out.println(command);
while ((line = input.readLine()) != null)
{
line = line.trim();
System.out.println(line);
}
System.out.println("done");
}
catch (IOException ioException)
{
ioException.printStackTrace();
}
However, the line returned by the InputStream is always null, even though if I put the command used in .exec() into cmd (I printed it so I know they are the exact same), it works properly, albeit after a 5 seconds or so of delay. I tried it with 2 different process names and they both worked on cmd, but not in this java program. This is the output of the above code, in case that helps (the blank line is presumably from the \n at the end of the command string):
tasklist /v /fo list /fi "imagename eq notepad*"| find /i "window title:"
done
I tried adding p.waitFor() after calling .exec(), but that didn't seem to change anything. So what am I doing wrong here?
You have two problems with launching the command. Firstly you are ignoring error stream so don't see the actual problem.
Replace p = Runtime.getRuntime().exec(command); with ProcessBuilder to get access to error message:
ProcessBuilder pb = new ProcessBuilder(command);
pb.redirectErrorStream();
p = pb.start();
This will tell you that tasklist is not a process. Normally using full pathname would fix this type of error, but as you are using pipe the whole command must sent to to CMD.EXE to interpret pipe components correctly. Run CMD.EXE then your piped command:
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", command);
pb.redirectErrorStream();
p = pb.start();
Prints:
tasklist /v /fo list /fi "imagename eq notepad*"| find /i "window title:"
Window Title: Notepad++
done
It's also easier to read STDOUT with simple transfer:
try(var stdout = p.getInputStream()) {
stdout.transferTo(System.out); // or where-ever
}
Using java, I run cmd to be able to execute a ttl file.
My code:
try {
String[] command = new String[] {"cmd.exe", "/c", "cd C:\software\teraterm", "& TTPMacro C:\file\execute.ttl param1 param2 param3"};
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
} catch (Exception e) {
throw e;
}
But I want cmd to be run as admin
so I added runas /savecred /user:.\Administrator in my code,
but it is not working anymore:
try {
String[] command = new String[] {"cmd.exe", "/c", "runas /savecred /user:.\\Administrator", "cd C:\software\teraterm", "& TTPMacro C:\file\execute.ttl param1 param2 param3"};
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
} catch (Exception e) {
throw e;
}
What is wrong with this?
I've updated code to check input stream, but there is no output
try {
String[] command = new String[] {"cmd.exe", "/c", "runas /savecred /user:.\\Administrator", "cd C:\software\teraterm", "& TTPMacro C:\file\execute.ttl param1 param2 param3"};
Process p = Runtime.getRuntime().exec(command);
BufferedReader br=new BufferedReader(new InputStreamReader(p.getInputStream()));
String l;
while((l=br.readLine()) != null){
System.out.print(l);
}
p.waitFor();
} catch (Exception e) {
throw e;
}
Meta: although not stated, this Q and A is only for Windows and is useless on other systems
runas can only run a program (with arguments); cd is a builtin function of cmd not a program. Also cmdone & cmdtwo is a feature of cmd, not something runas can do. You need to put your commands into a cmd /c invocation, much as you did for running directly from Java Runtime.exec (which also can only run a single program), except that runas requires its program-to-run to be exactly one argument, not optionally several that are (re)joined. So:
String[] command = new String[]{"runas","/user:administrator","/savecred", // these must be separated args
"cmd /c cd directory & executable data"}; // these must be all one argument
Also in Java String literals, backslash is used as an escape character, so you must double each one (in pathnames or otherwise).
Finally if runas doesn't have already-saved credentials it prompts for the password. This prompt is not a line, so you can't read it with BufferedReader.readLine(). You can read it as bytes (into an array) with the input stream, or chars (ditto) with the InputStreamReader. However, as something of a hack, since runas doesn't pass its own stdhandles to its child but instead a new console window, you can just ignore the prompt and always write the password to p.getOutputStream() whether it's needed or not, and if it's not it will be discarded.
If I run the following in a terminal I get the expected 123
$ /bin/sh
$ FOO=123
$ echo $FOO
123
Now I try to do the following with Java's Runtime's exec():
String[] envp = { "FOO=123" };
String cmd = "echo $FOO";
Process p = Runtime.getRuntime().exec(cmd, envp);
java.io.BufferedReader reader =
new java.io.BufferedReader(
new java.io.InputStreamReader(p.getInputStream()
)
);
System.out.println(reader.readLine());
I expect to see 123 but instead I get $FOO.
What am I missing?
The following works under Windows.
String[] envp = { "FOO=123" };
String cmd = "cmd /c echo %FOO%";
Process p = Runtime.getRuntime().exec(cmd, envp);
p.waitFor();
java.io.BufferedReader reader =
new java.io.BufferedReader(
new java.io.InputStreamReader(p.getInputStream()
)
);
String line;
while((line = reader.readLine()) != null) {
System.out.println(line);
}
What am I missing?
Firstly,
$ FOO=123
sets a shell variable. It is local to the shell. If you want a variable to be in the environment that child processes see, you must export it.
$ export FOO=123
But that's not the problem.
The real issue is the command string "echo $FOO". The problem is that $FOO is shell syntax .... but when you run a command from Java using exec:
exec itself doesn't understand shell syntax, and
exec doesn't run the command in a shell.
So the parameter that is given to the echo command consists of the literal string $FOO ... and that is what it outputs.
There are three approaches to solving this:
Interpolate the variable in Java; e.g.
String[] cmd = {"echo", "123"};
Process p = Runtime.getRuntime().exec(cmd);
or by doing repeated search / replace for things that look like variables. (But this only deals with environment variable interpolation, not other forms of shell substitution.)
Assuming that you are doing something more complicated than echo, write the command that you are running to do its own interpolation of environment variables. (This is clunky ...)
Explicitly invoke the command in a shell; e.g.
String[] envp = {"FOO=123"};
String[] cmd = {"/bin/sh", "-c", "echo $FOO"};
Process p = Runtime.getRuntime().exec(cmd, envp);
Note that you can use any shell, and provide pretty much any shell-ism that can be expressed in a single shell command line.
Hey all I am trying to change directories and then run my command with parameters.
final String path = "\\Local// Apps\\IBM\\SDP\\scmtools\\eclipse";
final String command = "scm help";
final String dosCommand = "cmd /c \"" + path + "\"" + command;
final Process process = Runtime.getRuntime().exec(dosCommand);
final InputStream in = process.getInputStream();
int ch;
while((ch = in.read()) != -1) {
System.out.print((char)ch);
}
It runs without errors but outputs nothing. However, this is what shows up after it finishes:
<terminated, exit value: 0>C:\Local Apps\IBM\SDP\jdk\bin\javaw.exe (Jul 22, 2019, 11:21:37 AM)
The expected output should be:
So am I doing this correctly?
AS suggested by Andreas
Process p = null;
ProcessBuilder pb = new ProcessBuilder("scm.exe");
pb.directory(new File("C:/Local Apps/IBM/SDP/scmtools/eclipse"));
p = pb.start();
I get the following error:
Cannot run program "scm.exe" (in directory "C:\Local Apps\IBM\SDP\scmtools\eclipse"): CreateProcess error=2, The system cannot find the file specified
You should use ProcessBuilder instead of Runtime.exec, e.g.
Process proc = new ProcessBuilder("scm.exe", "help")
.directory(new File("C:\\Local Apps\\IBM\\SDP\\scmtools\\eclipse"))
.inheritIO()
.start();
proc.waitFor(); // optional
You can also go through the command interpreter if needed, e.g. if the command is a script (.bat or .cmd file):
Process proc = new ProcessBuilder("cmd", "/c", "scm", "help")
.directory(new File("C:\\Local Apps\\IBM\\SDP\\scmtools\\eclipse"))
.inheritIO()
.start();
proc.waitFor();
The inheritIO() means that you don't need to process the commands output. It will be sent to the console, or wherever Java's own output would go.
I got stuck while trying to run bfgminer.exe -o bla.bla.com -u <nick> -p <passwd> -S auto -d all
I tried a number of ways to run this executable, but I can't get it to work:
public static void runCmd(){
try{
ProcessBuilder builder = new ProcessBuilder("cmd.exe","/c", "cd \"C:\\Users\\pawisoon\\bfgminer-3.10.0-win64\" && bfgminer.exe -o bla.bla.com -u <user> -p
<pswd> -S auto -d all");
builder.redirectErrorStream(true);
Process pd = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(pd.getInputStream()));
String line;
while (true) {
line = r.readLine();
if (line == null) { break; }
System.out.println(line);
}
}
catch(IOException e){
}
}
This is what I got from console in Eclipse:
'bfgminer.exe' is not recognized as an internal or external command,
operable program or batch file.
Please help me how to solve this problem :/
Thanks a lot for your answers ! I combined your advises and it worked. Here is code :
public static void runCmd(){
File f = new File("C:\\Users\\pawisoon\\bfgminer-3.10.0-win64");
try{
ProcessBuilder builder = new ProcessBuilder("cmd.exe","/c","start","bfgminer.exe", "-o", "bla.bala.com", "-u", "user", "-p", "lelelel", "-S", "auto", "-d", "all");
builder.directory(f);
builder.redirectErrorStream(true);
Process pd = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(pd.getInputStream()));
String line;
while (true) {
line = r.readLine();
if (line == null) { break; }
System.out.println(line);
}
}
catch(IOException e){
}
}
From what I see, you try to execute
cd C:\Users\pawisoon\bfgminer-3.10.0-win64\
And then
bfgminer.exe -o bla.bla.com -u -p -S auto -d all
because I imagine bfgminer.exe is in the suppposed actual repertory (C:\Users\pawisoon\bfgminer-3.10.0-win64)
But actually I'm not sure your two cmd commands are correctly executed (I mean: I'm not sure the repertory is kept as a reference for the execution of the second command)
So why don't just try to execute
C:\Users\pawisoon\bfgminer-3.10.0-win64\bfgminer.exe -o bla.bla.com -u -p -S auto -d all
(no cd and full path to the executable)
Or check out #ginz comment and try to launch the executable directly (not using cmd) if you don't especially want to use cmd.exe