I'm not able to read unicode strings passed as VM arguments, if I launch the process from Eclipse IDE.
For example:
ArrayList<String> commands = new ArrayList<>();
commands.add("java");
commands.add("-classpath");
commands.add("bin");
commands.add("-Dprop=ÁÉÍÓÚ");
commands.add("test.ReadProp");
ProcessBuilder pb = new ProcessBuilder(commands);
Process process = pb.start();
BufferedReader in;
String line;
in = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((line = in.readLine()) != null)
System.out.println(line);
With test.ReadProp
String prop = System.getProperty("prop");
System.out.println("prop: " + prop);
The result is
prop: ??????????
The only solution seems to force the environment variable LANG in this way
pb.environment().put("LANG", "it_IT.UTF-8");
There are better solutions?
More portable?
Updated at 20:30
Another solution seems to be adding the environment LANG=it_IT.UTF-8 to the BASH script that launches the Eclipse process. But it is not something that I can control on every computer.
Pass -Dfile.encoding=UTF8 to the JVM.
I'm using Eclipse Version: 2019-09 R (4.13.0) in Windows 10 and what it worked for me was:
Control panel -> Regional settings -> Administrative tab-> Change system locale...
and setting the specific language I wanted to use (in my case, it was Greek)
Activating the Beta feature screwed things up so my setting is OFF
Related
I'm trying to execute a command in my terminal. The problem is, when I execute the command in terminal, it succeed, but when I run the command from java, the command is executed but, I got an error message showing me that some python module is missing.
try{
String[] list = { "python3", "script.py" };
ProcessBuilder pb = new ProcessBuilder(list);
pb.directory(
new File("/home/script"));
System.out.println("" + pb.directory());
Process process = pb.start();
InputStream str = process.getErrorStream();
InputStreamReader isr = new InputStreamReader(str);
BufferedReader br = new BufferedReader(isr);
String line;
System.out.printf("Output of running %s is:", Arrays.toString(args));
while ((line = br.readLine()) != null) {
System.out.println(line);}
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String ret = in.readLine();
System.out.println("value is : "+ret);
process.waitFor();
process.destroy();
}catch (Exception ex) {
ex.printStackTrace();
}
The error message:
/home/script
Output of running [] is:Traceback (most recent call last):
File "scraper.py", line 8, in <module>
from selenium import webdriver
ModuleNotFoundError: No module named 'selenium'
value is : null
PS: When I execute the command directly from terminal, everything works good, I don't get the missing module error.
Similar to Java, python allows to import other stuff. That message tells you that your python script wants to use the module selenium, but can't find it.
Most likely you have some special ENV var setup when running commands manually in a shell/console. So check your .bashrc or .initrc or whatever defines your ENV variables. On a unix system, typing the command env might show you all settings, too. Simply check if the env var PYTHONPATH is setup.
As that call works from the command line, then for sure, the module is installed on your system. Your only problem is that python can't find it when you invoke that script through the Java ProcessBuilder!
One solution might be that you "manually" adjust the PYTHONPATH from within your script. Thus: figure the correct setup for PYTHONPATH, then update your script to "do the right thing".
For further details, see the python documentation!
What I want to do is I want to run a process, however because this process itself relies on environment variables, directly calling it causes error within the process. For those who are wondering what this is, it's rake tool. For this reason I thought maybe it's better to use bash and using it through bash would eliminate the issue. However that doesn't seem to be the case.
Here is my code:
public static void runPB(String directory) throws IOException {
ProcessBuilder processBuilder = new ProcessBuilder(
"/bin/bash");
processBuilder.directory(new File(directory));
Process process = processBuilder.start();
OutputStreamWriter osw = new OutputStreamWriter(process.getOutputStream());
osw.write("rake routes");
osw.close();
printStream(process.getErrorStream());
printStream(process.getInputStream());
}
public static void printStream(InputStream is) throws IOException {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
I know it is environment related issue because the error that I am getting is described here cannot load such file -- bundler/setup (LoadError)
Further I checked processBuilder.environment() returns less environment variables than entering env. I went ahead and changed the osw.write() line and tried echo $GEM_HOME there, which doesn't print anything and if I do this on my OSs bash then I get the path, I also tried other common things like echo $SHELL and it prints the shell location in both Java code and in bash.
So my questions are:
1) Why is my operating system's environment variables are different than the ProcessBuilder.environment() method?
2) Does Process class consider using environment variables that were given out by ProcessBuilder.environment()? If so then how can we add the missing ones from the operating system's level?
1) The varaibles you see in your java process are those inheritd from the process you started the java process from. I.e. If you launch it from a shell it should have the same variables as the shell had. You need to investigate which variables are actually set before launching your Java application and why the ones you expect are not set in that context.
To answer part 2, yes, the process will be launched with the environment in ProcessBuilder.environment(). You can simply add things to the map returned by ProcessBuilder.environment(), that will extend the runtime environment:
ProcessBuilder pb = new ProcessBuilder("foo");
pb.environment().put("MY_VAR", "foobar");
This question already has answers here:
How do I set environment variables from Java?
(23 answers)
Closed 8 years ago.
I want to set environment variable in JAVA . For this , I have searched a lot in internet and got the following code .
void set_up_environment_var() throws IOException
{
ProcessBuilder pb = new ProcessBuilder("CMD.exe", "/C", "SET"); // SET prints out the environment variables
pb.redirectErrorStream(true);
Map<String,String> env = pb.environment();
String str1 = ";C:\\naved\\bin";
String path = env.get("Path") ;//+ ";C:\\naved\\bin";
System.out.println("ok , I am coming . "+path.toLowerCase().contains(str1.toLowerCase()));
env.put("Path", path.concat(str1));
Process process = pb.start();
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = in.readLine()) != null)
{
// System.out.println(line);
}
}
But after execution , the envorinment variable is not set in "PATH" varaible . Why ?
A process can only set environment variables of itself and for processes it will spawn in future. A process cannot set the environment variables of already running processes.
You might have already noticed that when you were setting environment variables manually, globally in the system. They will not affect instances of processes which are already running, like an already running cmd.exe or an already running bash. You might also have noticed, that if you set an environment variable that way, that whether or not a new process gets the new environment variable setting depends on how the new process is started. The default behavior is that a process is started with a copy of the environment of its parent process, which is the process that starts the new process.
As a simple explanation, you could say there are root processes and child processes. root processes get the environment settings from the global settings, child processes inherit the environment settings from their parent processes.
The question is what do you want to achieve with setting the environment? I could think of at least three different things that you could want to achieve:
Set the environment globally, as part of an installer.
Set the environment for the currently running JVM.
Set the environment for a process that you will be starting.
Set the environment for the calling process directly (not possible!).
Set the environment for the calling process indirectly.
Setting the environment globally, as part of an installer
This is highly system-specific.
On UNIX, this topic is actually avoided.
Programs would rather provide wrapper scripts that set the environment instead of setting global environment variables.
The philosophy in UNIX is that usually environment variables are only used in cases where the variable would be useful for more than just one process.
Examples for such varaibles are PATH and EDITOR.
On Windows, you would probably call regedit to modify the environment.
Setting the environment of the currently running JVM
There is no API for setting the environment of the currently running JVM, so you would have to use JNI for this. However, be advised, that the fact that there is no API for this is for good reasons, and part of these reasons might be that the JVM doesn't want its environment be arbitrarily changed by some Java code.
Setting the environment for a process that will be started
When you start a process using one of the Runtime.exec() methods, you can actually provide the environment that you like.
If you want to start a process with a modified environment, the best way would be to use ProcessBuilder. It provides a method environment() for modifying the environment for the new process.
Setting the environment for the calling process directly
If you want to implement the set command in Java, forget it, it is not possible. set is not a program, it's an internal command of the shell, i.e. cmd.exe. Because of the explanation above, it wouldn't work otherwise.
Setting the environment for the calling process indirectly
You can set the environment for the calling process indirectly - if the calling process cooperates. If your calling process is cmd.exe or sh, you could have your Java program generate a temporary batch file or shell script, and then have the calling cmd.exe or sh execute that batch file or shell script.
Simple example for how to set path with setx.exe in command line:
setx path "jdk bin path"
ex
setx path "C:\Program Files (x86)\Java\jdk1.7.0_04\bin"
try this on your code
like
try {
// using the Runtime exec method:
Process p = Runtime.getRuntime().exec("setx path C:\Program Files (x86)\Java\jdk1.7.0_04\bin");
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
// read the output from the command
System.out.println("Here is the standard output of the command:\n");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
System.exit(0);
}
catch (IOException e) {
System.out.println("exception happened - here's what I know: ");
e.printStackTrace();
System.exit(-1);
}
I am working on a Java program that has to fetch the machine serial number, CPU serial number etc. On Windows, the WMI interface is the best way to query for such information, and the standard way to query using the commandline is
wmic bios get serialnumber
which produces output:
SerialNumber
WWV46RT609A3467173E
Translating this into Java, I have used both Runtime.exec() and a ProcessBuilder like so:
(The commented Process p is what I did previously). Here, component and item correspond to 'bios' and 'serialnumber' in the commandline above.
String ret = "";
ProcessBuilder pb = new ProcessBuilder("wmic", component, "get", item);
pb.redirectErrorStream(true);
// Process p = Runtime.getRuntime().exec(
// "wmic " + component + " get " + item);
Process p = pb.start();
InputStreamReader isr = new InputStreamReader(p.getInputStream());
BufferedReader input = new BufferedReader(isr);
String str;
while ((str = input.readLine()) != null) {
if (str.equalsIgnoreCase(item) || StringUtils.isBlank(str)) {
continue;
}
ret = str.trim();
}
input.close();
isr.close();
System.out.println(ret);
This snippet works perfectly on Windows 7, but hangs on Windows XP. Using wmic from the commandline works on both OSes.
I read here that there's a problem with handling both stdout and stderr of the called process, hence the redirectErrorStream() call.
Why does it work flawlessly on Windows 7 but fail on XP? Is there a way other than spawning a separate thread, aka 'StreamGobbler'? (The linked example is quite ancient, and predates the ProcessBuilder class, with its redirectErrorStream() call.
I hope that you have by now got a resolution to this issue. If not, this is what you need to do. First, I also encountered with the same issues and came to discover that it is bufferedReader issue. It is gets into a deadlock situation that resulting into windows xp hanging. The solution is to simulate the end of line (eof) to the bufferedreader by appending "<NUL" the the command.
String[] command = {"CMD", "/C", "WMIC COMPUTERSYSTEM GET USERNAME <NUL "} and executing this command.
You have to use threads to capture ouputs (standard & error).
You can also take a look at this Apache library.
I want to get the path name and arguments of running processes using java code. Is there any solution?
For instance, on Windows, one possibility is to encapsulate the system call to TASKLIST.EXE
Extract from the code:
Process p = Runtime.getRuntime().exec("tasklist.exe /fo csv /nh");
BufferedReader input = new BufferedReader
(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
if (!line.trim().equals("")) {
// keep only the process name
line = line.substring(1);
processes.add(line.substring(0, line.indexOf(""")));
}
}
You should use tasklist /V though, since it comes with the parameters of the processes.
You could use the SIGAR framework, which gives you native support for Linux, FreeBSD, Windows, Solaris, AIX, HP-UX and Mac OSX