You should really look at Process Builder. It is really built for this kind of thing.
ProcessBuilder pb = new ProcessBuilder("myshellScript.sh", "myArg1", "myArg2");
Map<String, String> env = pb.environment();
env.put("VAR1", "myValue");
env.remove("OTHERVAR");
env.put("VAR2", env.get("VAR1") + "suffix");
pb.directory(new File("myDir"));
Process p = pb.start();
Answer from Milhous on Stack OverflowYou should really look at Process Builder. It is really built for this kind of thing.
ProcessBuilder pb = new ProcessBuilder("myshellScript.sh", "myArg1", "myArg2");
Map<String, String> env = pb.environment();
env.put("VAR1", "myValue");
env.remove("OTHERVAR");
env.put("VAR2", env.get("VAR1") + "suffix");
pb.directory(new File("myDir"));
Process p = pb.start();
You can use Apache Commons exec library also.
Example :
package testShellScript;
import java.io.IOException;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
public class TestScript {
int iExitValue;
String sCommandString;
public void runScript(String command){
sCommandString = command;
CommandLine oCmdLine = CommandLine.parse(sCommandString);
DefaultExecutor oDefaultExecutor = new DefaultExecutor();
oDefaultExecutor.setExitValue(0);
try {
iExitValue = oDefaultExecutor.execute(oCmdLine);
} catch (ExecuteException e) {
System.err.println("Execution failed.");
e.printStackTrace();
} catch (IOException e) {
System.err.println("permission denied.");
e.printStackTrace();
}
}
public static void main(String args[]){
TestScript testScript = new TestScript();
testScript.runScript("sh /root/Desktop/testScript.sh");
}
}
For further reference, An example is given on Apache Doc also.
Videos
create a file named "sync" in /usr/bin containing the following:
java -jar {PATH TO JARFILE}
2
Replace {PATH TO JARFILE} with the path to the jarfile
Make the file executable by typing chmod +x sync while in /usr/bin
you can create a shell with name say "run.sh" (note .sh extension which tell it is a shell script) and copy it in /usr/local/bin directory.
1.Script (run.sh)
#!/bin/sh
arg1=$1
arg2=$2
##directory where jar file is located
dir=/directory-path/to/jar-file/
##jar file name
jar_name=json-simple-1.1.1.jar
## Permform some validation on input arguments, one example below
if [ -z "
2" ]; then
echo "Missing arguments, exiting.."
echo "Usage : $0 arg1 arg2"
exit 1
fi
java -jar
jar_name arg1 arg2
copy the script in /usr/local/bin
cp run.sh /usr/local/bin
Give execute permission to the script
chmod u+x /usr/local/bin/test.sh
now you can type just word run or run.sh on command line : shell will auto-complete the script name and also it can executed by pressing enter key.
I don't know anything about Java, but I can show you a proof of concept. Say we have localfile.txt:
Here is the local file.
and on the remote machine, we have remote.sh:
#!/bin/bash
cat /dev/stdin
Note that the script on the remote machine invokes a program which reads from stdin. Then pass the contents of localfile.txt to your ssh command:
user@local:~$ cat localfile.txt | ssh user@remote remote.sh
Here is the local file.
Your Java program is trying to read a file which does not exist on the remote machine. I guess you could try to mimic a local file.
Change remote.sh to:
#!/bin/bash
cat "$@"
and invoke it with
user@local:~$ cat localfile.txt | ssh user@remote 'remote.sh <(cat /dev/stdin)'
Here is the local file.
I think it would be easier to change that part in your Java program to read from stdin.
I guess things might get messy if localfile.txt contains anything that might be interpreted by the shell as expandable (such as *), but that's for you to figure out.
The problem is that the shell redirection (<) sends the file over the ssh tunnel. And the Java class is expecting not the file, but a string with the "filename" of a local file that will be read with a FileReader.
Instead of passing the filename to the FileReader, read from the standard input.
InputStreamReader isReader = new InputStreamReader(System.in);
BufferedReader iR = new BufferedReader (isReader);
Used this as a reference: https://stackoverflow.com/questions/5724646/how-to-pipe-input-to-java-program-with-bash
Now your class will be:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.OutputStreamWriter;
import java.io.InputStreamReader;
public class ReadFirstLine
{
public static void main(String[] args) throws Exception
{
String filename = args[0];
System.out.println(filename);
//BufferedReader iR = new BufferedReader (new FileReader(filename));
InputStreamReader isReader = new InputStreamReader(System.in);
BufferedReader iR = new BufferedReader (isReader);
BufferedWriter oW = new BufferedWriter(new OutputStreamWriter(System.out));
//outputWriter.write(iR.readLine());
System.out.println(iR.readLine());
iR.close();
oW.close();
}
}
But for this task I would definitely use instead:
head -1 filename.txt
:)
You should use the returned Process to get the result.
Runtime#exec executes the command as a separate process and returns an object of type Process. You should call Process#waitFor so that your program waits until the new process finishes. Then, you can invoke Process.html#getOutputStream() on the returned Process object to inspect the output of the executed command.
An alternative way of creating a process is to use ProcessBuilder.
Process p = new ProcessBuilder("myCommand", "myArg").start();
With a ProcessBuilder, you list the arguments of the command as separate arguments.
See Difference between ProcessBuilder and Runtime.exec() and ProcessBuilder vs Runtime.exec() to learn more about the differences between Runtime#exec and ProcessBuilder#start.
When you execute a script from Java it spawns a new shell where the PATH environment variable is not set.
Setting the PATH env variable using the below code should run your script.
String[] env = {"PATH=/bin:/usr/bin/"};
String cmd = "you complete shell command"; //e.g test.sh -dparam1 -oout.txt
Process process = Runtime.getRuntime().exec(cmd, env);
You need to tell java where to look for your class (using -cp) - either in a directory or a .jar
To find the directory where the script is (as opposed to where it was launched from), you can use: $(dirname $0).
So, for example:
#!/bin/bash
JVM=java
JVM_OPTS="-Xmx1024m"
$JVM $JVM_OPTS -cp $(dirname $0)/myapp.jar A1 "$@"
It's a good idea to be explicit about the shell you want. Also note the quotes around $@, needed for escaped args.
Use the classpath flag when running java to tell the virtual machine where your A1.class file is located.
See the doc
Should be something like:
java -classpath /myfolder A1 $@
Also, do not use the ".class" suffix when running the command.