How to set environment variable in java [duplicate] - java

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);
}

Related

How to perform java command prompt action on unix

I have two jar files named test1.jar and test2.jar.
In order to execute a function in in this jar file, I run below command in cmd.
“java getOutput argument1 argument2 argument3 argument4”
As a pre-requisite, I have set the following entries in my system environment variables to execute the java function using the above command.
1.CLASSPATH=C:\Folder\test1.jar;C:\Folder\test2.jar;C:\Program Files\Java\jre1.8.0_181\lib\plugin.jar
2.JAVA_BIN=C:\Program Files\Java\jre1.8.0_181\bin
3.JAVA_HOME=C:\Program Files\Java\jre1.8.0_181
4.PATH = C:\Program Files\Java\jre1.8.0_181\bin
The output of the above command is a string.
I have another java code. I have to capture the above string output in a variable in my java program and I am able to do this by using below java code in eclipse.
String strArgs= strArg1+" "+strArg2+" "+strArg3+" "+strArg4;
Process p=Runtime.getRuntime().exec("cmd /c java getOutput "+strArgs+"");
BufferedReader input =new BufferedReader(new
InputStreamReader(p.getInputStream()));
String strOutput = input.readLine();
if (strOutput != null) {
System.out.println(strOutput);
String strVariable = strOutput;
input.close();
}else {
System.out.println("FAIL- Output not generated");
}
In order to execute the above code on unix, I replace Line 2 with "Process p=Runtime.getRuntime().exec("usr/bin/java getOutput "+strArgs+"");" , convert the eclipse java project into a jar file named automation.jar. And I try to execute this jar file on unix using the below command .
`java -cp automation.jar Package.MainClass.'
When I run the code I get the output as null. But when I run the command on windows command prompt I get the output string.
Could you please help me on how to set the system variables in unix and perform the above operation to generate the string output.
Please let me know if any additional information required.
cmd is windows only. Unix uses a shell. But you shouldn't need either here. Just remove the cmd call.
Process p = Runtime.getRuntime().exec("java getOutput " + strArgs);
If it can't find Java, you can read the JAVA_BIN (or JAVA_HOME) from the environment.
String java_bin = System.getenv("JAVA_BIN");
Process p = Runtime.getRuntime().exec(java_bin + "/java getOutput " + strArgs);
Finally, your environment variables look like Windows path variables. Make sure they're correct for your Unix environment (Unix doesn't have a "C" drive).

Running a process inside a folder on Linux in Java

So I have a JAR program that runs and reads the output of a command line Linux app. This app is located in a temp folder, which is where my JAR is.
Here's the Java code for reading the output:
Process proc;
ProcessBuilder pb = new ProcessBuilder();
pb.command("temp/myapp", "arg1");
pb.redirectErrorStream(true);
try {
proc = pb.start();
} catch (IOException ex) {
System.out.println("ERROR: Couldn't start process");
}
scan = new Scanner(proc.getInputStream());
String line = "";
while (scan.hasNext())
line += scan.nextLine() + System.lineSeparator();
scan.close();
Later I return that String I read into of course.
Now, the problem is that Scanner throws a NullPointerException, which means that the process cannot be found or cannot be run.
The moment I take the executable out of the temp and use
pb.command("./myapp", "arg1");
My program works perfectly fine.
If I open Terminal where the JAR is, temp/myapp arg1 will return exactly what it should. It's only the Java code that cannot seem to run this inside temp.
The question is, how do I point at the CLI app inside temp, if not the way I described above?
PS: The Java app works on Windows in the same setup, using pb.command("temp/myapp", "arg1") and a Win version of myapp so this is a Linux-specific issue.
I think it is not getting the process at respective path. Try by giving the absolute path of the process and then execute. Hope it will work.
I found the solution.
ProcessBuilder's directory() method, which I also use somewhere, sets not only the working directory of the Process, but also the directory where the Process will be launched from, on Linux at least, so how my code was actually parsed on Linux was temp/temp/myapp. When I set temp as the working directory, I only had to use ./myapp to launch it from temp. On Windows (my primary platform), this is not the case, I still have to use pass temp/myapp as parameter in command().

Java processbuilder and using environment variables

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");

How to pass unicode VM arguments with eclipse?

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

How to use "cd" command using Java runtime?

I've created a standalone java application in which I'm trying to change the directory using the "cd" command in Ubuntu 10.04 terminal. I've used the following code.
String[] command = new String[]{"cd",path};
Process child = Runtime.getRuntime().exec(command, null);
But the above code gives the following error
Exception in thread "main" java.io.IOException: Cannot run program "cd": java.io.IOException: error=2, No such file or directory
Can anyone please tell me how to implement it?
There is no executable called cd, because it can't be implemented in a separate process.
The problem is that each process has its own current working directory and implementing cd as a separate process would only ever change that processes current working directory.
In a Java program you can't change your current working directory and you shouldn't need to. Simply use absolute file paths.
The one case where the current working directory matters is executing an external process (using ProcessBuilder or Runtime.exec()). In those cases you can specify the working directory to use for the newly started process explicitly (ProcessBuilder.directory() and the three-argument Runtime.exec() respectively).
Note: the current working directory can be read from the system property user.dir. You might feel tempted to set that system property. Note that doing so will lead to very bad inconsistencies, because it's not meant to be writable.
See the link below (this explains how to do it):
http://alvinalexander.com/java/edu/pj/pj010016
i.e. :
String[] cmd = { "/bin/sh", "-c", "cd /var; ls -l" };
Process p = Runtime.getRuntime().exec(cmd);
Have you explored this exec command for a java Runtime, Create a file object with the path you want to "cd" to and then input it as a third parameter for the exec method.
public Process exec(String command,
String[] envp,
File dir)
throws IOException
Executes the specified string command in a separate process with the specified environment and working directory.
This is a convenience method. An invocation of the form exec(command, envp, dir) behaves in exactly the same way as the invocation exec(cmdarray, envp, dir), where cmdarray is an array of all the tokens in command.
More precisely, the command string is broken into tokens using a StringTokenizer created by the call new StringTokenizer(command) with no further modification of the character categories. The tokens produced by the tokenizer are then placed in the new string array cmdarray, in the same order.
Parameters:
command - a specified system command.
envp - array of strings, each element of which has environment variable settings in the format name=value, or null if the subprocess should inherit the environment of the current process.
dir - the working directory of the subprocess, or null if the subprocess should inherit the working directory of the current process.
Returns:
A new Process object for managing the subprocess
Throws:
SecurityException - If a security manager exists and its checkExec method doesn't allow creation of the subprocess
IOException - If an I/O error occurs
NullPointerException - If command is null, or one of the elements of envp is null
IllegalArgumentException - If command is empty
This command works just fine
Runtime.getRuntime().exec(sh -c 'cd /path/to/dir && ProgToExecute)
Using one of the process builder's method we could pass the directory where we expect the cmd to be executed. Please see the below example. Also , you can mention the timeout for the process, using wait for method.
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", cmd).directory(new File(path));
Process p = builder.start();
p.waitFor(timeoutSec, TimeUnit.SECONDS);
In the above code, you can pass the file object of the path[where we expect the cmd to be executed] to the directory method of ProcessBuilder
My preferred solution for this is to pass in the directory that the Runtime process will run in. I would create a little method like follows: -
public static String cmd(File dir, String command) {
System.out.println("> " + command); // better to use e.g. Slf4j
System.out.println();
try {
Process p = Runtime.getRuntime().exec(command, null, dir);
String result = IOUtils.toString(p.getInputStream(), Charset.defaultCharset());
String error = IOUtils.toString(p.getErrorStream(), Charset.defaultCharset());
if (error != null && !error.isEmpty()) { // throw exception if error stream
throw new RuntimeException(error);
}
System.out.println(result); // better to use e.g. Slf4j
return result; // return result for optional additional processing
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Note that this uses the Apache Commons IO library i.e. add to pom.xml
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.10.0</version>
</dependency>
To use the cmd method e.g.
public static void main(String[] args) throws Exception {
File dir = new File("/Users/bob/code/test-repo");
cmd(dir, "git status");
cmd(dir, "git pull");
}
This will output something like this: -
> git status
On branch main
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
> git pull
Already up to date.
Try Use:
Runtime.getRuntime.exec("cmd /c cd path");
This worked
Runtime r = Runtime.getRuntime();
r.exec("cmd /c pdftk C:\\tmp\\trashhtml_to_pdf\\b.pdf C:\\tmp\\trashhtml_to_pdf\\a.pdf cat output C:\\tmp\\trashhtml_to_pdf\\d.pdf");
The below did not work
While using array command did NOT WORK
String[] cmd = {"cmd /c pdftk C:\\tmp\\trashhtml_to_pdf\\b.pdf C:\\tmp\\trashhtml_to_pdf\\a.pdf cat output C:\\tmp\\trashhtml_to_pdf\\d.pdf"}; r.exec(cmd);
FYI am using utility to check OS if its windows above will work for other than windows remove cmd and /c
I had solved this by having the Java application execute a sh script which was in the same directory and then in the sh script had done the "cd".
It was required that I do a "cd" to a specific directory so the target application could work properly.

Categories

Resources