I am using c-shell and I am used to using setenv. I need to execute an equivalent command from within a python script. I tried using os.environ['JAVA_HOME'] = "/usr/local/java" which works from the python interpreter, but when my script is executed from the command line, the shell it ran in does reflect the newly set environment variable. Can anybody help, I am new to scripting, I hope I made my question clear.
If you're using subprocess.Popen, it should be enough to pass the env parameter to the constructor to whatever you need as a dictionary (you can copy the contents of os.environ and add your own environment variables if you wish).
As explained in How to use export with Python on Linux, setting an environment variable within any process (such as your Python script) cannot affect any parent processes (such as the csh process from which you execute the Python script).
What you can do is have your Python script print a setenv command, and then evaluate the output in your shell as a command.
For example:
csh% cat foo.py
#!/usr/bin/python
import os;
os.environ["JAVA_HOME"] = "/usr/local/java"
print "setenv JAVA_HOME", os.environ["JAVA_HOME"]
csh% ./foo.py
setenv JAVA_HOME /usr/local/java
csh% echo $JAVA_HOME
JAVA_HOME: Undefined variable.
csh% eval `./foo.py`
csh% echo $JAVA_HOME
/usr/local/java
csh%
And you can set up an alias in your ~/.cshrc to do the eval `...`, or just invoke it directly from your .cshrc or .login (depending on just what you're trying to accomplish).
I know it is been a while sins this issue, but I solved it a little different.
Maybe this ain't even the most beautiful solution, but it works.
I created a shell script called env.sh
#!/bin/tcsh
eval $*
Then in my python script called subprocess.
output = subprocess.Popen(["env.sh", "setenv", "DISPLAY", "remhost:0"], stdout = subprocess.PIPE).communicate()[0].split()
This works for me, don't forget to make the env.sh executable by executing "chmod +x env.sh"
Related
This command works great from terminal $java -jar $picard
Whenever I put that in bash script, It gives error as: line 2: -jar: command not found
#!/bin/sh
$java -jar $picard`
Is there any fix, thanks?
The $ at the beginning of the line is not part of the command; it is part of the shell prompt.
When you put the command in a batch file, you should not include the shell prompt. So change it to:
#!/bin/sh
java -jar $picard
EDIT
OP mentioned that "$java" points to the actual Java binary.
If you are following naming conventions for shell scripts then $java and $picard are local variables in your shell, not environment variables, so they don't get passed onto any commands that you invoke.
To turn them into environment variables, you need to export them from your shell. Whereever you set values in them is the best place to put:
export java
export picard
However, this turns them into environment variables, and in that case you should make the names "all capitals" -> JAVA, PICARD.
You have to export the java variable which you are using to point to java path as below
JAVA_CLASSPATH=/bin/jre1.8.0_101/bin/java
export PICARD_CLASSPATH=/bin/picard-tools-2.5.0/picard.jar
$JAVA_CLASSPATH -classpath $PICARD_CLASSPATH {Nmae of the Class from where the execution begins}
Instead of using small case you can use capital letter so it will be more readable.
Environment: mac
Precondition: I already configured 'adb' full path to my bash_profile. and when I tried type 'adb' in my terminal, it is working.
But, I tried to exec 'adb' command from java, 'adb' is not working, instead I need to pass the full adb path to make it work.
I guess this is probably something to do with the bash_profile setting, anyone know the exact reason for this issue?
Runtime.getRuntime().exec() runs /bin/sh -c <command>. If this is or points to a bash shell on your system: A non-interactive bash does not read .bash_profile unless explicitly (--login) told to do so.
From the documentation:
When Bash is invoked as an interactive login shell, or as a non-interactive shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable. The --noprofile option may be used when the shell is started to inhibit this behavior.
It's a little convoluted, but non-interactive, non-login bash instances don't read the profile files.
Your path settings does not get picked up by the subshell (which is actually /bin/sh which might not even be bash at all).
If you want, you can add the path to adb system wide by adding an appropriate entry to to /etc/paths.d.
I used to use Debian's alternatives system to set 'global env' like java, javac, javap but I've read about the disadvantages.
So I added
export JAVA_HOME=/opt/jdk/java
export PATH=$JAVA_HOME/bin:$PATH
to my ~/.bashrc and when I open my terminal I can use the commands as expected but my most of my shell scripts doesn't work anymore.
As you can see in the picture below they check if $JAVA_HOME exists and executes the following command which does nothing. When I enter $JAVA_HOME/bin/java -version it works correctly. If I start the script in a terminal it works, too.
So it seems that #!/bin/sh doesn't source .bashrc? Changing it to #!/bin/bash doesn't solve the problem.
I tried to add the export commands to /etc/profile but this doesn't seem to get sourced at startup/login.
Does anyone have an idea or keywords? I think the solution is quite simple but at the moment I'm stuck.
Thank you in advance!
UPDATE:
Starting the script in the bash terminal with ./something.sh works fine. Right click and execute or 'Open with bash' (XFCE4 context menu) does nothing.
Bash loads .bashrc only when the shell is interactive and non-login. In your case the shell is not interactive, so .bashrc is not loaded.
.bashrc contains a check that prevents it from executing if the shell is not interactive. Usually the first thing .bashrc does is:
case $- in
*i*) ;;
*) return;;
esac
This will prevent you from calling source .bashrc from your script.
The script should inherit from your parent shell, so you should be getting all variable that have been exported before you ran the script.
Also, the preferred shebang is #!/usr/bin/env bash which is more portable.
So in your case:
Open a terminal window. That will load .bashrc, but just to make sure, run . .bashrc and then echo $JAVA_HOME to verify that the variable was set correctly.
Then your script will simply be:
#!/usr/bin/env bash
java -jar <whatever>
If you have some other script related variable that you want to set, you can do that by sourcing a "settings" script:
#!/usr/bin/env bash
source ~/settings.sh
echo $SOME_VAR_SET_IN_SETTINGS_SH
Adding additional folders to your PATH variable in XFCE4 with LightDM will not work as expected! Shell scripts that use these additional commands and are started from the graphical environment will fail because the can't find the command. Logging the PATH variable while starting one of these scripts shows that the PATH variable is overwritten with the very default one. Why? Because LightDM hardcodes the PATH variable and overwrites it for the graphical environment. Screw you! Look here!
Source: https://ljwo.wordpress.com/2014/02/02/global-path-in-debian-wheezy-xfce/
Disable it or use another DM.
I have a binary executable (no source code) which requires this command to be executed in the terminal - export LD_LIBRARY_PATH = "" to link to a library lbtiff.so.3 which I have in a directory. Only after I execute this export command, I can execute the binary, otherwise it gives an error - "error while loading shared libraries: libtiff.so.3...
Now, I want to execute this binary from my java code. But simply executing the export command in the runtime does not do anything and the "error while .." error still occurs when I execute the binary from Java. I guess setting the unix specific environment variable LD_LIBRARY_PATH might not be possible from Java - is there a way I can run my binary from Java and it is able to find the libraries? Here's my current code -
Process p = Runtime.getRuntime().exec("bash -c export LD_LIBRARY_PATH=<lib path>");
p = Runtime.getRuntime().exec("<binary path>");
Rather than Runtime.exec, use ProcessBuilder. That will allow you to specify environment variables when you run the binary that requires them
ProcessBuilder pb = new ProcessBuilder("<binarypath>");
pb.environment().put("LD_LIBRARY_PATH", "<libPath>");
Process p = pb.start();
Your approach with two separate Runtime.exec calls will not work, because the environment settings you make in the first one only affect that particular Process, not subsequent processes started by a separate invocation of Runtime.exec.
See my answer to another question. The best way is to not use an external shell to set the environment variable (your code doesn't work because it will not set the variable globally, only for the bash process), but to set the variable from within Java. Much easier and it works (and on all platforms, regardless of which shell is installed).
On unix systems you can prepend the variable before executing the command
LD_LIBRARY_PATH=... foo args
Will execute the program foo with args using the modified LD_LIBRARY_PATH
Or you could take advantage of the subshell by using:
(export LD_LIBRARY_PATH=...; foo args)
I am trying to call my linux executable from shell script. Before calling this executable, I want to set LD_LIBRARY_PATH with specific values. My shell script is as below:
Parent.sh (contains 2 lines)
- source set_env.sh
- executable.so
Set_env.sh
- setenv LD_LIBRARY_PATH /proj/something
On manually executing Parent.sh scipt from linux console, the executable.so is called with LD_LIBRARY_PATH set correctly. But after integrating it wiht java code as:
String[] commandArray ={"Parent.sh"};
Runtime runtime = Runtime.getRuntime();
Process javap = runtime.exec(commandArray);
javap.waitFor();
LD_LIBRARY_PATH is not set for executable.so
I hope description is clear :)
Please let know whats wrong in the code.
Dunes answer solves your problem, but I would strongly suggest a different approach in this particular case. Instead of relying on a shell to set the environment arguments, you should do this in your Java code. This way you don't need to know which shells exist on the system and what their language is, it will just work on all platforms.
To do this, you can use the Runtime.exec(String[] cmd, String[] environment) overload (javadoc). As the second parameter you can pass an array which contains all the environment variables the subprocess will see.
A little bit nicer even is the ProcessBuilder API:
ProcessBuilder pb = new ProcessBuilder("executable.so");
Map<String, String> env = pb.environment();
env.put("LD_LIBRARY_PATH", "/proj/something");
Process javap = pb.start();
javap.waitFor();
This way, the subprocess will inherit all environment variables from the Java process, and additionally have the LD_LIBRARY_PATH variable set.
Are you sure the subprocess is using csh? If it starts up using bash or something else then this would prevent the script from working (but not to throw an IOException).
You should really aad a hashbang line as the very first line of your script to state which shell interpreter you wish to use.
eg.
#!/usr/bin/env csh