Reputation: 12347
I am using Groovy to execute commands on my Linux box and get back the output, but I am not able to use |
pipes somehow (I think) or maybe it is not waiting for the command to finish.
What is wrong or what am I missing in my code?
My calling function:
def test()
{
String result="N"
HashMap<String,String> params = IntermediateResults.get("userparams")
Map env=AppContext.get(AppCtxProperties.environmentVariables)
def fClass = new GroovyClassLoader().parseClass( new File( 'plugins/infa9/Infa9CommandExecUtil.groovy' ) )
List<String> frows=["uname -a",
"uname -a | awk '{print\$2}'",
"uname -a | cut -d ' ' -f 2"]
List<String> resultRows = fClass.newInstance().fetchCommandOutput( params, env, frows )
return result
}
Infa9CommandExecUtil.groovy
file content (update: added exitVal println):
package infa9
import java.io.BufferedReader;
public class Infa9CommandExecUtil {
StringBuffer result
public Infa9CommandExecUtil() {
result = new StringBuffer()
}
public List<String> fetchCommandOutput( Map<String,String> params, Map env, List<String> rows )
{
List<String> outputRows = new ArrayList<String>()
try
{
for(item in rows)
{
String temp=item.toString()
println "CMD:$temp"
Process proc = Runtime.getRuntime().exec(temp);
InputStream stdin = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(stdin);
BufferedReader br = new BufferedReader(isr);
String line = null;
result = new StringBuffer()
line=null
int exitVal = proc.waitFor() //do I need to wait for the thread/process to finish here?
while ((line = br.readLine()) != null)
{
result.append(line+System.getProperty("line.separator")) //to maintain the format (newlines)
}
String tRes=result
tRes=tRes.trim()
println "OUTPUT:$tRes\nEXITVAL:$exitVal"
outputRows.add(tRes)
}
}
catch (IOException io) { io.printStackTrace();}
catch (InterruptedException ie) {ie.printStackTrace();}
return outputRows
}
}
My output (update: added exitVal value):
CMD:uname -a
OUTPUT:Linux estilo 2.6.18-128.el5 #1 SMP Wed Dec 17 11:41:38 EST 2008 x86_64 x86_64 x86_64 GNU/Linux
EXITVAL:0
CMD:uname -a | awk '{print$2}'
OUTPUT:
EXITVAL:1
CMD:uname -a | cut -d ' ' -f 2
OUTPUT:
EXITVAL:1
Note: I am internally using sh -c <command>
.
Upvotes: 4
Views: 10868
Reputation: 171084
You cannot do pipes or redirects using String.execute()
. This doesn't work in Java, so it doesn't work in Groovy either...
You can use Process.pipeTo
with Groovy to simplify things:
Process proca = 'uname -a'.execute()
Process procb = 'awk {print\$2}'.execute()
(proca | procb).text
A more generic version could be:
String process = 'uname -a | awk {print\$2}'
// Split the string into sections based on |
// And pipe the results together
Process result = process.tokenize( '|' ).inject( null ) { p, c ->
if( p )
p | c.execute()
else
c.execute()
}
// Print out the output and error streams
result.waitForProcessOutput( System.out, System.out )
Upvotes: 12
Reputation: 533500
The pipe |
is a feature of a shell like bash. To use a pipe you need to run a shell, like
"/bin/bash", "-c", "uname -a | awk '{print $2}'"
To use ProcessBuilder with redirection you can do
public static void main(String... args) throws IOException, InterruptedException {
final String cmd = "uname -a | awk '{print $1 \" \" $3}'";
System.out.println(cmd + " => " + run(cmd));
}
private static String run(String cmd) throws IOException, InterruptedException {
final ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", cmd);
pb.redirectErrorStream();
final Process process = pb.start();
final InputStream in = process.getInputStream();
final byte[] bytes = new byte[1024];
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
// you must read the output as the program runs or it can stall.
for (int len; (len = in.read(bytes)) > 0;)
baos.write(bytes, 0, len);
process.waitFor();
return baos.toString(); // assuming the default char encoding is ok.
}
prints
uname -a | awk '{print $1 " " $3}' => Linux 2.6.18-274.3.1.el5
Upvotes: 4
Reputation: 115328
Pipe is a feature of shell. So if you want pipes to be supported you have to run your command in shell context, i.e. your command line that you pass to exec
in java should look like /bin/sh YOUR_COMMAND
.
Upvotes: 1