Unable to get output from shell script command in java - java

I'm running a shell script command in java program using ProcessBuilder, here is my code :
String lastLine = "";
ProcessBuilder processBuilder = new ProcessBuilder("/bin/bash", "-c", "echo $(ps -eo pid,args | grep -v grep | grep -v \"$$"\ | grep feature_service.sh | awk '{print $1}')");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
lastLine = line;
}
Output from this : empty string ("")
But if i run the same command on terminal it is working fine (pid of process).
Please help me.

Following simplified Shell command is working.
ProcessBuilder processBuilder = new ProcessBuilder("/bin/bash",
"-c",
"ps -eo pid,args|grep [f]eature_service.sh|awk '{print $1}'|tr '\\n' ' '");
ps -eo pid,args - list the process ID and the arguments
grep [f]eature_service.sh - grep for the string feature_service.sh in the arguments, the [f] avoid the multiple usage of grep in the chain
awk '{print $1}' - print the first column of the output, using default whitespace characters as delimiter
tr '\n' ' ' - replace all newline cracaters in the output by a space character

Related

Java Run Command pipe on linux

I am trying to get output of piped command in linux environment but so far no luck.
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "top", "-b", "-n", "2", "-d", "0.2", "-p", pid + "", "|", "tail", "-1", "|", "awk", "'{print $6}'");
pb.redirectErrorStream(true);
Process p = pb.start();
p.getOutputStream().close();
try (InputStream is = p.getInputStream()) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
String line = br.readLine();
System.out.println(line);
}
}
This outputs: top: failed tty get
When I try that without specifying the script executor (/bin/bash -c): top: unknown option '|'
The shell command should be a single argument passed after -c. The invoked shell will take care of the piping and tokenization:
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c",
"top -b -n 2 -d 0.2 -p " + pid + " | tail -1 | awk '{print $6}'");
For robustness bonus points, pass the variables as separate arguments instead of injecting them into the string (like how you'd use prepared statements in SQL):
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c",
"top -b -n 2 -d 0.2 -p \"$1\" | tail -1 | awk '{print $6}'", "_", String.valueOf(pid));
It makes no difference when pid is an integer, but if it's an arbitrary string, this improves security and robustness.

How to use Process Builder in java to run Linux shell command?

I am trying to execute two linux commands using JAVA program:
ifconfig| grep -A 1 'eth0'|tail -1|cut -d ':' -f 2|cut -d ' ' -f 1
This command gives me and "IP address" and I have to read and use it in the second command
./executeTest.sh "IP address"
My function which I am using to run these commands is this:
public int exec(String[] command, Map<String, String> envt, StringBuilder stdout, StringBuilder stderr, int timeoutSeconds) throws TimeoutException, Exception{
int exitValue = -1;
final File stdoutFile = File.createTempFile("test_", "extproc.out");
final File stderrFile = File.createTempFile("test_", "extproc.err");
Process process = null;
try{
ProcessBuilder pb = new ProcessBuilder(command);
if(envt!=null){
for(Entry<String, String> entry : envt.entrySet()){
pb.environment().put(entry.getKey(), entry.getValue());
}
}
pb.redirectOutput(stdoutFile);
pb.redirectError(stderrFile);
process = pb.start();
boolean timedOut = false;
timedOut = !(process.waitFor(timeoutSeconds, TimeUnit.SECONDS));
if(timedOut){
System.out.println("Timed out waiting for process to complete.");
try{
process.destroyForcibly();
}catch(Exception killEx){
System.out.println("Error while terminating runaway process"+ killEx);
}
}else{
exitValue = process.exitValue();
}
stdout.append(FileUtils.readFileToString(stdoutFile));
stderr.append(FileUtils.readFileToString(stderrFile));
if(timedOut){
throw new TimeoutException();
}
}finally{
if(stdoutFile.exists()){
//File.deleteDirectory(stdoutFile);
}
if(stderrFile.exists()){
//FileUtils.deleteDirectory(stdoutFile);
}
if(process != null){
process.destroy();
}
}
return exitValue;
}
However, I am getting the following error when I call this function for both the commands written above:
java.io.IOException: Cannot run program "ifconfig | grep -A 1 'eth0' | tail -1 |cut -d ':' -f 2 |cut -d ' ' -f 1": error=2, No such file or directory
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
at IOxUnifiedSanityTestSuite.starWebServer.exec(starWebServer.java:66)
at IOxUnifiedSanityTestSuite.starWebServer$2.handle(starWebServer.java:148)
at IOxUnifiedSanityTestSuite.starWebServer$2.handle(starWebServer.java:124)
at io.vertx.ext.web.impl.RouteImpl.handleContext(RouteImpl.java:217)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:78)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:133)
at io.vertx.ext.web.impl.RouterImpl.accept(RouterImpl.java:79)
at io.vertx.core.http.impl.ServerConnection.handleRequest(ServerConnection.java:288)
at io.vertx.core.http.impl.ServerConnection.processMessage(ServerConnection.java:421)
at io.vertx.core.http.impl.ServerConnection.handleMessage(ServerConnection.java:134)
at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:623)
at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:573)
at io.vertx.core.http.impl.VertxHttpHandler.lambda$channelRead$0(VertxHttpHandler.java:71)
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$2(ContextImpl.java:322)
at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:190)
at io.vertx.core.http.impl.VertxHttpHandler.channelRead(VertxHttpHandler.java:71)
at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:122)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:341)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:341)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:642)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:565)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:479)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:441)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: error=2, No such file or directory
at java.lang.UNIXProcess.forkAndExec(Native Method)
at java.lang.UNIXProcess.<init>(UNIXProcess.java:248)
at java.lang.ProcessImpl.start(ProcessImpl.java:134)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
... 36 more
The way I am calling exec function is this:
String command1[] = new String[]{"ifconfig | grep -A 1 \'eth0\' | tail -1 |cut -d \':\' -f 2 |cut -d \' \' -f 1"};
StringBuilder stdout = new StringBuilder();
StringBuilder stderr = new StringBuilder();
exec(command1, null, stdout, stderr, 30)
String command2[] = new String[]{"./executeTest.sh ipaddress"};
StringBuilder stdout1 = new StringBuilder();
StringBuilder stderr1 = new StringBuilder();
exec(command2, null, stdout1, stderr1, 30)
Can anyone help me in finding out what I am doing wrong here?
You probably feed your first command as a whole to ProcessBuilder's constructor:
"ifconfig| grep -A 1 'eth0'|tail -1|cut -d ':' -f 2|cut -d ' ' -f 1"
ProcessBuilder considers it to be a single program name, hence the error.
Try passing it the following:
new String{"/bin/bash", "-c", "ifconfig| grep -A 1 'eth0'|tail -1|cut -d ':' -f 2|cut -d ' ' -f 1"}
like
exec(new String{"/bin/bash", "-c", "ifconfig| grep -A 1 'eth0'|tail -1|cut -d ':' -f 2|cut -d ' ' -f 1"},
envt, stdout, stderr, timeoutSeconds);
ProcessBuilder will invoke bash, which in turn will invoke the complex command.

How to use ProcessBuilder when using redirection in Linux

I want to run this command using ProcessBuilder:
sort -m -u -T /dir -o output <(zcat big-zipped-file1.gz | sort -u) <(zcat big-zipped-file2.gz | sort -u) <(zcat big-zipped-file3.gz | sort -u)
I have tried the following:
// This doesn't recognise the redirection.
String[] args = new String[] {"sort", "-m", "-u", "-T", "/dir", "-o", "output", "<(zcat big-zipped-file1.gz | sort -u)", "<(zcat big-zipped-file2.gz | sort -u)", "<(zcat big-zipped-file3.gz | sort -u)"};
// This gives:
// /bin/sh: -c: line 0: syntax error near unexpected token `('
String[] args = new String[] {"/bin/sh", "-c", "\"sort -m -u -T /dir -o output <(zcat big-zipped-file1.gz | sort -u) <(zcat big-zipped-file2.gz | sort -u) <(zcat big-zipped-file3.gz | sort -u)\""};
I am using args like this: processBuilder.command(args);
I finally figured it out. As Roman has mentioned in his comment, sh does not understand redirection so I had to use bash. I also had to consume both the input stream and the error stream.
String[] args = new String[] {"/bin/bash", "-c", "sort -m -u -T /dir -o output <(zcat big-zipped-file1.gz | sort -u) <(zcat big-zipped-file2.gz | sort -u) <(zcat big-zipped-file3.gz | sort -u)"};
ProcessBuilder builder = new ProcessBuilder();
builder.command(args);
Process process = builder.start();
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader error = new BufferedReader(new InputStreamReader(process.getErrorStream()));
while((line = input.readLine()) != null);
while((line = error.readLine()) != null);
process.waitFor();

pipe Unix commands together in Java

I have a requirement to run the below command from Java
echo <inputMessage> | iconv -f utf8 -t Cp930
When i use the below code to run the command i see only the echo part is executed but the piping is not happening
public static String callInconverter2(String input,String codePage) throws IOException {
try{
// String command = "echo asdasdasd | iconv -f UTF-8 -t Cp930";
Process p = Runtime.getRuntime().exec("echo "+input+"| iconv -f UTF-8 -t "+codePage);
String s = null;
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
StringBuilder sb = new StringBuilder();
// read the output from the command
System.out.println("Here is the standard output of the command:\n");
while ((s = stdInput.readLine()) != null) {
sb.append(s);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
sb.append(s);
}
return sb.toString();
}
catch (IOException e) {
System.out.println("exception happened - here's what I know: ");
e.printStackTrace();
return e.getMessage();
}
}}
I am new to Runtime. is there anything am missing.
Tried the method suggested by thomas
String command = "echo asdasdasd | iconv -f UTF-8 -t Cp930";
Process p = Runtime.getRuntime().exec("bash -c \""+command+"\"");
was getting an error asdasdasd: -c: line 0: unexpected EOF while looking for matching `"'asdasdasd: -c: line 1: syntax error: unexpected end of file
is there anything am missing out
Run a shell, with that command -- bash, tcsh, whichever one you normally use.
bash -c "echo | iconv -f utf8 -t Cp930" // or
bash -lc "echo | iconv -f utf8 -t Cp930"
Piping is a shell functionality.
Thus:
Runtime rt = Runtime.getRuntime();
String cmd = "echo | iconv -f utf8 -t Cp930";
rt.exec("bash -c \""+cmd+"\"");
See the bash manual for invocation options. http://www.gnu.org/software/bash/manual/html_node/Invoking-Bash.html#Invoking-Bash

Java Runtime Process Won't "Grep"

I'm executing some commands from the command line in my java program, and it appears that it doesn't allow me to use "grep"? I've tested this by removing the "grep" portion and the command runs just fine!
My code that DOESN'T work:
String serviceL = "someService";
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("chkconfig --list | grep " + serviceL);
Code that does work:
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("chkconfig --list");
Why is this? And is there some sort of correct method or workaround? I'm aware that I could just parse the entire output, but I would find it easier to do it all from the command line. Thanks.
The pipe (like redirection, or >) is a function of the shell, and so executing it directly from Java won't work. You need to do something like:
/bin/sh -c "your | piped | commands | here"
which executes a shell process within the command line (including pipes) specified after the -c (in quotes).
So, here's is a sample code that works on my Linux OS.
public static void main(String[] args) throws IOException {
Runtime rt = Runtime.getRuntime();
String[] cmd = { "/bin/sh", "-c", "ps aux | grep skype" };
Process proc = rt.exec(cmd);
BufferedReader is = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line;
while ((line = is.readLine()) != null) {
System.out.println(line);
}
}
Here, I'm extracting all my 'Skype' processes and print the content of the process input stream.
You're trying to use piping which is a function of the shell ... and you're not using a shell; you're exec'ing the chkconfig process directly.
The easy solution would be to exec the shell and have it do everything:
Process proc = rt.exec("/bin/sh -c chkconfig --list | grep " + serviceL);
That being said ... why are you piping to grep? Just read the output of chkconfig and do the matching yourself in java.
String[] commands = { "bash", "-c", "chkconfig --list | grep " + serviceL };
Process p = Runtime.getRuntime().exec(commands);
or if you are in a linux env just use grep4j

Categories