Learner
Learner

Reputation: 1634

Execute shell script in Java and read Output

I am executing the shell script using below method in java

public static void main(String ar[])
{
  //key value are being read from properties file, here I am assigning the sample values      directly

   key=mine
   value="ls-1|tail-1"


  String[] cmd = { "jj.sh" , key,value};
  Process script_exec = Runtime.getRuntime().exec(cmd);
  script_exec.waitFor();
  if(script_exec.exitValue() != 0){
   System.out.println("Error while executing script");

  BufferedReader stdInput = new BufferedReader(new
                InputStreamReader(script_exec.getInputStream()));

  while ((s = stdInput.readLine()) != null) {
                System.out.println(s);
            }
}

The jj.sh file contains below value

#!/bin/sh

key=$1
value=`$2` 
echo $value

When I execute jj.sh using key and value directly, it give me the correct value, that is, the name of file. However with java it is giving me the result as ls -1 result (Means java is ignoring the command after '|'). When I pass the key values delimited with tilde sign ` then it simply displays the full key value i.e. ls -1|tail -1

How to execute the full command using java

Upvotes: 6

Views: 40609

Answers (2)

that other guy
that other guy

Reputation: 123400

The primary reason why this doesn't work is that `$2` is not the same as `ls -1 | tail -1`, even when $2 is set to that string.

If your script accepts a literal string with a command to execute, you can use eval to do so.

I created a complete example. Please copy-paste it and verify that it works before you try applying any of it to your own code. Here's Test.java:

import java.io.*;

public class Test {
  public static void main(String[] args) throws Exception {
    String[] command = { "./myscript", "key", "ls -t | tail -n 1" };
    Process process = Runtime.getRuntime().exec(command);
    BufferedReader reader = new BufferedReader(new InputStreamReader(
        process.getInputStream()));
    String s;
    while ((s = reader.readLine()) != null) {
      System.out.println("Script output: " + s);
    }
  }
}

And myscript:

#!/bin/bash
key="$1"
value=$(eval "$2")
echo "The command  $2  evaluated to: $value"

Here's how we can run myscript separately:

$ ls -t | tail -n 1
Templates

$ ./myscript foo 'ls -t | tail -n 1'
The command  ls -t | tail -n 1  evaluated to: Templates

And here's the result of running the Java code:

$ javac Test.java && java Test
Script output: The command  ls -t | tail -n 1  evaluated to: Templates 

Upvotes: 14

miw
miw

Reputation: 764

As other posters pointed out already, the sub-process is not started in a shell, so the she-bang is not interpreted.

I got your example to work by explicitly starting the evaluation of the second parameter in a shell in jj.sh:

value=`sh -c "$2"` 

Not nice, but works.

Other option may be to start the script in a shell explicitly, emulating the sh-bang:

String[] cmd = { "/bin/sh", "jj.sh" , key,value};

Upvotes: 0

Related Questions