How do I start a terminal from Mac OS from a java program?
The code that I have tried are
String[] arg = new String[] {"/bin/bash", "-c", "Terminal"};
Process proc = new ProcessBuilder(arg).start();
OutputStream out = null;
Process proc = new ProcessBuilder("Terminal").start();
Runtime.getRuntime().exec("/bin/bash -c Terminal");
out = proc.getOutputStream();
out.write("cd /home/me/Desktop/".getBytes());
out.flush();
However both of em didnt work. Any help would be appreciated.
The following command works for me just give the absolute path of your terminal app and it should work fine.
Runtime.getRuntime().exec("/bin/bash -c /Applications/Utilities/Terminal.app/Contents/MacOS/Terminal");
Related
If I run the following in a terminal I get the expected 123
$ /bin/sh
$ FOO=123
$ echo $FOO
123
Now I try to do the following with Java's Runtime's exec():
String[] envp = { "FOO=123" };
String cmd = "echo $FOO";
Process p = Runtime.getRuntime().exec(cmd, envp);
java.io.BufferedReader reader =
new java.io.BufferedReader(
new java.io.InputStreamReader(p.getInputStream()
)
);
System.out.println(reader.readLine());
I expect to see 123 but instead I get $FOO.
What am I missing?
The following works under Windows.
String[] envp = { "FOO=123" };
String cmd = "cmd /c echo %FOO%";
Process p = Runtime.getRuntime().exec(cmd, envp);
p.waitFor();
java.io.BufferedReader reader =
new java.io.BufferedReader(
new java.io.InputStreamReader(p.getInputStream()
)
);
String line;
while((line = reader.readLine()) != null) {
System.out.println(line);
}
What am I missing?
Firstly,
$ FOO=123
sets a shell variable. It is local to the shell. If you want a variable to be in the environment that child processes see, you must export it.
$ export FOO=123
But that's not the problem.
The real issue is the command string "echo $FOO". The problem is that $FOO is shell syntax .... but when you run a command from Java using exec:
exec itself doesn't understand shell syntax, and
exec doesn't run the command in a shell.
So the parameter that is given to the echo command consists of the literal string $FOO ... and that is what it outputs.
There are three approaches to solving this:
Interpolate the variable in Java; e.g.
String[] cmd = {"echo", "123"};
Process p = Runtime.getRuntime().exec(cmd);
or by doing repeated search / replace for things that look like variables. (But this only deals with environment variable interpolation, not other forms of shell substitution.)
Assuming that you are doing something more complicated than echo, write the command that you are running to do its own interpolation of environment variables. (This is clunky ...)
Explicitly invoke the command in a shell; e.g.
String[] envp = {"FOO=123"};
String[] cmd = {"/bin/sh", "-c", "echo $FOO"};
Process p = Runtime.getRuntime().exec(cmd, envp);
Note that you can use any shell, and provide pretty much any shell-ism that can be expressed in a single shell command line.
I'm trying to get the output of grep linux shell command in java by using process builder. But i got a stuck in this case. Please help me.
Thank in advice!
String[] args = new String[7];
args[0] = "/bin/bash";
args[1] = "-c";
args[2] = "grep";
args[3] = "-n";
args[4] = "-e";
args[5] = "KERNELVERSION";
args[6] = kernelFilePath.trim();
ProcessBuilder pb;
Process process = null;
try {
pb = new ProcessBuilder(args);
pb = pb.directory(new File(directory));
pb.inheritIO();
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
process = pb.start();
process.waitFor();
} catch (IOException | InterruptedException e) {
System.out.println("executeCmdWithOutput() exception : " + e.toString());
} finally {
if (process != null) {
process.destroy();
}
}
==> Error:
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.
I tried the command in bash and it worked fine:
grep -n -e KERNELVERSION ..../Makefile
Have you tried change the args[2] as full command?
Also, you can use pgrep, it does not require you to use pipe.
You don't need to explicitly run /bin/bash in order to execute the grep process. Just call it directly and ProcessBuilder will run it:
String[] args = {"grep", "-n", "KERNELVERSION", kernelFilePath.trim()};
Also, you don't need to use the -e option, unless there are multiple patterns that you are searching for.
If you really wanted to run grep in /bin/bash:
String[] args = {"/bin/bash", "-c", "grep -n KERNELVERSION " + kernelFilePath.trim()};
passes a single argument to bash containing the full command and arguments to execute.
I need to start a server using bash, so I had created an UNIX shell , but I am not able to execute it with Java from Eclipse.
I tried the following code which doesn't work :
Process proc = Runtime.getRuntime().exec(./startServer);
Here is content of the startServer file :
#!/bin/bash
cd /Users/sujitsoni/Documents/bet/client
npm start
You can try the following two options.
Option 1
Process proc = Runtime.getRuntime().exec("/bin/bash", "-c", "<Abosulte Path>/startServer");
Option 2
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", "<Absolute Path>/startServer");
pb.directory(new File("<Absolute Path>"));
Process proc = pb.start();
A couple Of things can go wrong:
The path to the file you have given might be wrong for eclipse it can take relative path but from the command line, it will take the absolute path.
error=13, Permission denied - If the script file doesn't have required permissions. In your scenario, that might not the case as you are not getting any error.
At last, you are executing the script by java program so the output of your script will not be printed out. In your scenario, this might be the case. You need to capture the output of script from BufferedReade and print it. ( In your case server might have started but you are not seeing the logs/output of the script.
See the code sample below for printing output.
public static void main(String[] args) throws IOException, InterruptedException {
Process proc = Runtime.getRuntime().exec("./startServer");
proc.waitFor();
StringBuffer output = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
System.out.println(output);
}
I'm currently using ProcessBuilder to run some file like test.out.
Here is some of my code
ArrayList cmd = new ArrayList();
cmd.add("sudo");
cmd.add("./test.out");
String s = "";
try{
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.directory(new File("/myPath"));
pb.redircErrorStream(true);
Process p = pb.start();
InputStream is = p.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferReader br = new BufferReader(isr);
String line = "";
while((line = br.readLine()) !=null)
{
s+=line;
}
System.out.println(s);
}
I output the path which is correct("/myPath").
when I remove line
`cmd.add("sudo")`
the output will give me a String:
oneoflib:must be root. Did you forgot sudo?
But once I add
cmd.add("sudo");
there is nothing output.
Is there anyone whats wrong with it?
I can run sudo ./test.out from terminal which works fine.
I'm using eclipse BTW.
Thank you very much.
I guess that getting the error stream from the process could be beneficial here to help debug the problem.
This should help, consider the following bash script and let's call it yourExecutable. Let's also assume that it has all the proper permissions:
if [ "$EUID" -ne 0 ]
then echo "Please run as root"
exit
fi
echo "You are running as root"
When run without sudo it prints "Please run as root" other wise it prints "You are running as root"
The command, ie first argument in your list should be bash, if that is the shell you are using. The first argument should be -c so the commands will be read from the following string. The string should be echo <password> | sudo -S ./yourExecutable. This isn't exactly the best way to send the password to sudo, but I don't think that is the point here. The -S to sudo will prompt for the password which is written to stdout and piped over to sudo.
public static void main(String[] args) throws IOException {
Process process = new ProcessBuilder("bash", "-c", "echo <password> | sudo -S ./yourExecutable").start();
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String string;
while((string = errorReader.readLine()) != null){
System.out.println(string);
}
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
while((string = reader.readLine()) != null){
System.out.println(string);
}
}
Output on my machine looks like:
Password:
You are running as root
I need to run a command at terminal in Fedora 16 from a JAVA program. I tried using
Runtime.getRuntime().exec("xterm");
but this just opens the terminal, i am unable to execute any command.
I also tried this:
OutputStream out = null;
Process proc = new ProcessBuilder("xterm").start();
out = proc.getOutputStream();
out.write("any command".getBytes());
out.flush();
but still i can only open the terminal, but can't run the command.
Any ideas as to how to do it?
You need to run it using bash executable like this:
Runtime.getRuntime().exec("/bin/bash -c your_command");
Update:
As suggested by xav, it is advisable to use ProcessBuilder instead:
String[] args = new String[] {"/bin/bash", "-c", "your_command", "with", "args"};
Process proc = new ProcessBuilder(args).start();
I vote for Karthik T's answer. you don't need to open a terminal to run commands.
For example,
// file: RunShellCommandFromJava.java
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class RunShellCommandFromJava {
public static void main(String[] args) {
String command = "ping -c 3 www.google.com";
Process proc = Runtime.getRuntime().exec(command);
// Read the output
BufferedReader reader =
new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = "";
while((line = reader.readLine()) != null) {
System.out.print(line + "\n");
}
proc.waitFor();
}
}
The output:
$ javac RunShellCommandFromJava.java
$ java RunShellCommandFromJava
PING http://google.com (123.125.81.12): 56 data bytes
64 bytes from 123.125.81.12: icmp_seq=0 ttl=59 time=108.771 ms
64 bytes from 123.125.81.12: icmp_seq=1 ttl=59 time=119.601 ms
64 bytes from 123.125.81.12: icmp_seq=2 ttl=59 time=11.004 ms
--- http://google.com ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 11.004/79.792/119.601/48.841 ms
You don't actually need to run a command from an xterm session, you can run it directly:
String[] arguments = new String[] {"/path/to/executable", "arg0", "arg1", "etc"};
Process proc = new ProcessBuilder(arguments).start();
If the process responds interactively to the input stream, and you want to inject values, then do what you did before:
OutputStream out = proc.getOutputStream();
out.write("command\n");
out.flush();
Don't forget the '\n' at the end though as most apps will use it to identify the end of a single command's input.
As others said, you may run your external program without xterm. However, if you want to run it in a terminal window, e.g. to let the user interact with it, xterm allows you to specify the program to run as parameter.
xterm -e any command
In Java code this becomes:
String[] command = { "xterm", "-e", "my", "command", "with", "parameters" };
Runtime.getRuntime().exec(command);
Or, using ProcessBuilder:
String[] command = { "xterm", "-e", "my", "command", "with", "parameters" };
Process proc = new ProcessBuilder(command).start();
I don't know why, but for some reason, the "/bin/bash" version didn't work for me.
Instead, the simpler version worked, following the example given here at Oracle Docs.
String[] args = new String[] {"ping", "www.google.com"};
Process proc = new ProcessBuilder(args).start();
I know this question is quite old, but here's a library that encapsulates the ProcessBuilder api.