Reputation: 1634
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
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
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