I am creating a little CLI java application.
I have some trouble to manage a consistent clear screen functionality on Windows.
All solutions I have found are based on detecting the operating system.
Something like:
System.getProperty("os.name").indexOf("win") >= 0
and apply one of the documented Java: Clear the console answer depending whether it is Windows or not.
The disadvantage of this approach is that the clear screen is not working the same way if you run your java application in a cmd, git-bash or a Cygwin terminal. You cannot apply the cmd clear screen inside git-bash and the other way arround.
Based on that I would prefer to detect the terminal I am running on.
I thought to check if a Linux specific command would fail using a ProcessBuilder as a way to detect that I am in a cmd terminal but all the one I could think of also exists in a cmd terminals: ls, grep, awk. It is maybe because I have a WSL (Windows Linux Subsystem) installed but I am not sure.
Is there a way to detect the terminal running the JVM?
A simple way to achieve this is to introspect the environment variables of a system process.
You can achieve this with ProcessBuilder by checking if the PS1 environment variable is defined.
This is the variable I found, it is maybe not completely robust and could be present in your Windows environment. In that case find an other one in the collection returned by ProcessBuilder.environment().
ProcessBuilder pb = new ProcessBuilder();
if(pb.environment().containsKey("PS1")) {
System.out.println("non Windows console");
} else {
System.out.println("Windows console");
}
Related
So I have a Docker network that has a Docker file with a bunch of information. I have a java program that is going to bring up the enviorment and then produce several commands to run within this enviorment. To be clear, the first command I need to run is NOT inside the Docker enviorment. I am having some challenges with the Process and Runtime classes.
First, say I wanted my java program to launch a new gnome terminal and then run a command to get into the docker network. I have this command,
Process process = Runtime.getRuntime().exec(new String[]{"gnome-terminal"});
Gnome terminal sucessfully comes up but any additional arguments I give in this array are just ignored. For example,
Process process = Runtime.getRuntime().exec(new String[]{"gnome-terminal","ls"});
Does not work. The command I ultimatly want to run would look something like this,
Process process = Runtime.getRuntime().exec(new String[]{"gnome-terminal","sudo","docker","exec","-it","sawtooth-shell-default", "bash"});
Second, Once I have this running, will additional commmands I run work within the Docker enviorment? I have a python file with a Stream handler that specifies the correct commands to run.
Other documentation on related issues was limited.
I made sure my code was wrapped in a runtime exception try catch and that I was running the correct .class file. Any help on this would be great!
Edit: I have also tried to run this in another linux terminal like Hyper and Tilda
I also am able to get a sudo sign in when I run the command like so,
Process process = Runtime.getRuntime().exec(new String[]{"gnome-terminal","--","sudo","docker","exec","-it","sawtooth-shell-default", "bash"});
However it closes immediatly after authorizing.
Okay this is what I was attempting to do.
https://www.atlassian.com/blog/software-teams/deploy-java-apps-with-docker-awesome
This site is outdated and I had to use this link for getting that latest version of the java PPA.
This process basically installs java into the docker contatiner so that I can run a java program that uses Runtime.
When I execute a command using ProcessBuilder, how does it know where to look for that command? Using this hack/trick I've modified my PATH variable (verified by inspecting processBuilder.environment()) to be bad (empty, working dir, etc) but ProcessBuilder can still execute sort, echo, bash, etc. just fine. How is it doing this?!
Note: My particular development environment is OSX but this code will also run on Red Hat Enterprise Linux.
The documentation says
[...] a command, a list of strings which signifies the external program file to be invoked and its arguments, if any. Which string lists represent a valid operating system command is system-dependent. [...]
Which in essence mean that where it looks for programs to execute depends on the particular system and JVM you're running on.
I can't find a complete matrix of JVM / System behaviors, but supposedly it behaves similar to the popular shells of the system (bash for *nix and cmd for windows) i.e. it searches the directories in the PATH environment variable from left to right and executes the first executable file it finds.
If you want to take control of finding commands, then, well, take control of finding commands. Don't let ProcessBuilder search. Use your own code to find what you want to run, and then put an absolute pathname into the parameter to ProcessBuilder.
I have a JAVA application that launches (using ProcessBuilder) another JAVA application like this:
String val = "something";
ProcessBuilder processBuilder = new ProcessBuilder("java", "-classpath", dir, appName, val);
Process p = processBuilder.start();
Now, this works fine, appName is launched with the parameter val and it runs and works ... great ... the problem is no Console Window appears ... appName does a LOT of outputting to the console and we need to see it ... how can I start the process with a console?
I am trying stuff like ("CMD.exe", "java", "-classpath", dir, appName, val), etc... but I can't get it right ...
Also, I can't redirect the streams, my program can actually start 5-10 of these appName's, each should have their own console window showing their own information.
Any help would be much appreciated.
Thanks,
console windows are generally not the most reliable form of logging. they only store a set amount of information (buffer) and can behave differently across platforms.
i strongly suggest logging to a file using something like log4j and if you need to see it real time use a tail like program (i see you're using windows).
in addition to this, seeing as you want the windows visible at all times and launching a tail program for each log might be annoying, i'd write my own log window in java swing.
the basic idea is to not rely on the OS too much.
Tried Runtime.getRuntime().exec("cscript java -classpath ..."); ?
Anyway, consider using a logging framwork (log4j, commons-logging), because opening 5 consoles is not the most clever thing to do.
I call a few shell scripts via Process to open a command line window and launch whatever I need. As long as the scripts don't detach - you can usually stop any shell command from doing this -java will still hold the running process.
I did it in linux but the concept should be similar.
#!/bin/bash
# To open a process in a new window.
gnome-terminal -x ./your-real-shell-script-here.sh "$#"
the real script will have your java execution in it, such as:
#!/bin/bash
java -jar your-jar-file.jar "$#"
I think you can use javaw to run on windows, so you might only need the one shell script.
A Console object only exists when you execute java.... from a console. Otherwise, the call to obtain one returns null.
If you want to see a console, you need to open a command shell console (e.g. windows cmd.exe or Unix bash shell window) and type:
java -classpath="..." com.example.appName arg1
If you want to run in a different manner, sorry to say, logging to Console is not for you. Instead, log using one of:
log4j
slf4j
logback
I'm writing a Java Swing Application running on Red Hat Enterprise Linux 5 server that I would like to launch jEdit to view log files.
Here is some example code.
public static void main(String[] args) throws IOException, InterruptedException {
String cmd = "sh -c \"java -jar /tmp/jEdit/jedit.jar /tmp/test.txt\"";
System.out.println(cmd);
Runtime.getRuntime().exec(cmd);
}
The output is:
sh -c "java -jar /tmp/jEdit/jedit.jar /tmp/test.txt"
If I copy and paste the cmd output in a terminal window, it runs fine.
I have tried a bunch of cmd values, but I can never get the jEdit window to be visible.
With changes, this process works fine on Windows.
Is what I'm doing possible on Linux?
Thanks in advance!
As jEdit is implemented in Java, perhaps it would be easier to check the source for what the main method (in the class declared in the manifest file included in the jedit.jar) does and do the same thing without using Runtime.getRuntime().exec() at all.
If you do want to stick with it, you could try passing the individual commands as an array to exec(), this often solved such problems for me.
Linux uses the concept of display ports for its X-Windows system. This allows it to maintain a different desktop environment for each user. It also allows a user on remote machine to run a desktop app from the first machine but see the UI on the remote.
Windows, having only one available desktop environment at a time, does not.
First thing you definitely have to do is add the environment variable "DISPLAY=localhost:0" to the environment from which you are launching this. However, you may also need to run 'xhost +localhost' or this may not be allowed.
Double-check, too, that you didn't successfully launch a bunch of jEdit processes that are now zombies (using top) and kill them if necessary (using kill).
Runtime.exec() needs some special attention. The exec method that accepts a String uses the space character as a delimiter to break up the string into commands. You need to use the exec method that accepts a String[]. Read more here, specifically near the bottom.
I´ve done this once and I got the same problem
What I've done is to write the command line into a text file and then execute the text file as a shell script file.
It worked fine for me.
Jedit has a launcher script, /usr/bin/jedit I guess. Simply typing jedit in command prompt runs it, at least in current version, 4.5. Try that script instead of explicit java command.
I want to open the terminal (command prompt) on a Linux machine using Java code.
I know how to open command prompt in windows.The following code i have used in windows
String command= "cmd c/start cmd.exe"
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(command);
I need the same thing in Linux.
Thanks for your answers. I would like to run a sh script also.
Whether the following code works.
String command= "usr/bin/xterm myshell.sh";
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(command);
In Linux, there are a number of terminal emulators which allow you to interact with various shells. Each shell is basically a command interpreter that understands Linux commands (GNU & Unix commands is more correct I suppose...). A terminal emulator provides an interface (window) for the shell and some other facilities for using the command prompt. To open a terminal window, you just have to modify your command string like this:-
import java.io.*;
class TerminalLauncher
{
public static void main(String args[]) throws IOException
{
String command= "/usr/bin/xterm";
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(command);
}
}
The basic assumption I have made is that you want to open xterm, which is available on almost any system (with X installed of course). You might want to open another terminal emulator like rxvt, eterm, aterm, gnome-terminal or konsole. The command string can also be modified to use different shells like zsh. I suggest you catch an exception in case the terminal you chose isn't present and handle it by asking the user to install it. A better solution is to accept command line arguments for the users preferred shell or to use a configuration file which the user can change to make your script open the shell of his/her choice.
Note
1. As others have already pointed out, xterm (or any other terminal of your choice) may not be in the path specified (/usr/bin/...) and may not even be installed, so you might have to use some fancy command string (Ex: pipelining find through grep to get the path to xterm before launching), which isn't such a great idea. I think the best way is to let the user configure the whole thing.
2.I got a comment on this answer (by ypnos), suggesting that I avoid using absolute paths and rather rely on the command being in the PATH environment variable. I have to say I agree. In that case, the command string should be -
String command = "xterm"
Do look at the comment, because it also points out the problem with using find.
There's no single standard "terminal" command on Linux - the ones available depend on which GUI is present (i.e. whether KDE, or Gnome, etc).
You should be able to rely on xterm being present, but on modern Linux variants that's not the terminal of choice:
String command= "/usr/bin/xterm";
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(command);
Of course, "xterm" might not be in that particular path...
Under Gnome, it's gnome-terminal.
Under KDE, it's konsole.
Or you could use the more generic terminal program xterm.
You'll probably want to use options with most of this, so look up the man pages for the one you want.
xterm will most probably be available on most Linux-based operating systems and if present will be found in the path variable.
Therefore, you will need to do something like this:
try {
Runtime r = Runtime.getRuntime();
String myScript = .....
String[] cmdArray = {"xterm", "-e", myScript + " ; le_exec"};
r.exec(cmdArray).waitFor();
} catch (InterruptedException ex){
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
The -e option can be used to invoke either a script or another program, for example: javac. In this case you would make an assignment like: myScript = "javac".
You will need the " ; le_exec" part if you do not want the window to immediately close after execution, otherwise discard it. The semi-colon is used to separate commands and le_exec is just a simple script that waits for the user to press Enter.
However, if your script needs arguments, then you would need to replace the String myScript by and array of Strings.
I think it would be nice if your application will open user's default terminal application.
Unfortunately, it seems that there is no universal way to determine it.
In my opinion the most preferrable solution would be (stop whenever you can open something):
try to recongnize user's desktop environment and determine it's default terminal application. You can read something about it here.
check environment variable $TERM
Ask user for her preference and save it in configuration file.
Finding out user's desktop environment and it's default terminal might be too complicated for your purpose, so I'd use two last options.
You can run application from $TERM with code like this:
String command = System.getenv().get("TERM");
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(command);
There isn't actually a "the" terminal. What you really want is shell. Most Linuxes uses BaSH as a shell, but to keep on the safe side you should restrict yourself to /bin/sh
Edit: Hmm I probably missunderstood the question. If you want an interactive terminal you should look into using a toolkit providing a component for that.
Edit2: Maybe your needs can be served by VTE which is a GTK+ component for embedding a terminal.
I would definitely provide an easy way to configure the path to the desired terminal in a place that can be easily edited. For example maybe in a configuration XML file.
Different distros will keep this in different places, so it's probably best to check the per distribution documentation for the platforms you're targeting (and to document how to change it).
"/usr/bin/xterm" should be on most machines, but I wouldn't necessarily bet the farm on it.
since you have to assume you know almost nothing about the system you are running this on, I'd say lowest common denominator would be:
String command= "/bin/sh";
or even more 'guaranteed' -
String command= "sh";