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
Related
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 have noticed that some of my environment variables are not being picked up by the JVM.
In my .bash_profile I defined the following:
IO_HOME='some_value'
export IO_HOME
and by doing in shell:
echo $IO_HOME
I get the correct result.
But neither System.getProperties() nor System.getenv() is showing this variable being set. I tried both Java 6 and Java 7.
Is there something I am missing?
Exporting environment to spawned processes is pretty stable; if System.getenv() is not including a variable then it is because it is not in the environment. A couple of things to check, both relating to how the process is started:
Are you starting the java process from an environment where the variable is exported? For example, if it is in your .bash_profile and you are executing the java program from a menu or desktop then you have to log out and log in after adding it in .bash_profile for your desktop to see the variable.
Is the variable explicitly removed from environment for the process? ProcessBuilder allows this, as do most of all APIs that spawn processes.
One thing to try is to start the process from command line shell, after ensuring the variable is exported in that shell.
From Windows, I recently saw some crazy behaviour where IntelliJ refused to show all env vars from System.getenv() after setting either user or system env vars. The trick was to launch IntelliJ from a DOS box. For Windows users: Maybe a reboot (or logoff/logon) will fix the issue.
I've been having real problems trying to get a ruby script to run through Java. I've had all kinds of solutions proposed, and all of them are failing for some reason, so I'm trying to simplify my problem.
Let's say I have a shell script that just has this line in it:
ruby -rubygems script/test_s2t.rb
At the terminal, I can run this script using script/runruby.sh and it works as expected. Now let's say I have a Java method that does the following:
String[] cmd = {"script/runruby.sh"};
ProcessBuilder builder = new ProcessBuilder(cmd);
builder.redirectErrorStream(true);
Process process = builder.start();
This doesn't work (it throws an error back from the Ruby script, specifically, but this is a misdirect because it's really down to the script itself not working as expected). My question is not why that test_s2t.rb script doesn't work, because I think that might be distracting me from the real problem.
My question is simply what is different when I run something through ProcessBuilder as opposed to just running it via the command line. Is it a permissions thing? Path differences? There must be something screwing around with the environment the script runs in, because I can't see a problem with the script itself.
As alwyas, any suggestions appreciated. Three days and counting on this issue...
EDIT - For those curious, the exact error I receive in Java is the one described at the bottom of this question: Java receives an error executing Ruby script; Terminal doesn't
The outcome we got in that question was that I should try JRuby, but that resulted in further problems as I can't get the gems to work properly within JRuby. So I went back to asking myself why it wouldn't run normally in the first place.
The reason I think the error is a distraction is because the error is given simply because it processed a string it wasn't expecting to see. The string it expects is the normal process the script runs, which is using ffmpeg and suchlike. What this means is that the script encountered another error (which it isn't showing, which means it was probably not caused by ruby/jruby but by the processes the script launches like ffmpeg).
It's incredibly frustrating, purely because it runs so perfectly from the command line.
I've run into similar problems and there are two things that seem to be common problems:
1) The environment of the child process will be the same as environment of the current virtual machine. This includes the working directory of the launched process.
Example from: http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ProcessBuilder.html
Map<String, String> env = pb.environment();
env.put("VAR1", "myValue");
env.remove("OTHERVAR");
env.put("VAR2", env.get("VAR1") + "suffix");
pb.directory("myDir");
Alternatively, you could set the environment inside the shell script.
2) Do you have the proper shebang #! at the beginning of the .sh file? Personally I'd make it absolutely clear and perhaps explicitly call bash or zsh or whatever with the path to the shell script as the first argument OR directly call ruby with the '-rubygems' and 'script/test_s2t.rb' as arguments.
Good Luck!
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"
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";