views:

320

answers:

3

Hi,

I have a scenarios where I have a Java "agent" that runs on a couple of platforms (specifically Windows, Solaris & AIX). I'd like to factor out the differences in filesystem structure by using environment variables in the command line I execute.

As far as I can tell there is no way to get the Runtime.exec() method to resolve/evaluate any environment variables referenced in the command String (or array of Strings).

I know that if push comes to shove I can write some code to pre-process the command String(s) and resolve enviroment variables by hand (using getEnv() etc). However I'm wondering if there is a smarter way to do this since I'm sure I'm not the only person wanting to do this and I'm sure there are pitfalls in "knocking up" my own implementation.

Your guidance and suggestions are most welcome.

edit: I would like to refer to environment variables in the command string using some consistent notation such as $VAR and/or %VAR%. Not fussed which.

edit: To be clear I'd like to be able to execute a command such as:

perl $SCRIPT_ROOT/somePerlScript.pl args

on Windows and Unix hosts using Runtime.exec(). I specify the command in config file that describes a list of jobs to run and it has to be able to work cross platform, hence my thought that an environment variable would be useful to factor out the filesystem differences (/home/username/scripts vs C:\foo\scripts). Hope that helps clarify it.

Thanks. Tom

+1  A: 

Is there some reason system properties won't work? Use the -D flag on the command line, you can then retrieve it via System.getProperty

Steve B.
Hey Steve - I'm not sure how this would help? Perhaps my question isn't clear. I'll try to clarify it.
Tom Duckering
+1  A: 

I think I misunderstood your question with my original answer. If you are trying to resolve environment variable references on the command lines that you generated from with-in Java, I think you may have to "roll your own".

There are many different standards for how these are expanded, depending on the operating system. In addition, this is typically a function of the shell, so even on the same OS there could be different ways. In fact, standard operating system process activation functions (e.g. exec in Unix) do not do command line expansion.

This is really not that difficult, with Java 5 and later. Define a standard for yourself, I typically use the Java standard that you see in security policy files and some enhanced property file definitions - ${var} expands to the variable/property name reference. Something like:

    private static String expandCommandLine(final String cmd) {
        final Pattern vars = Pattern.compile("[$]\\{(\\S+)\\}");
        final Matcher m = vars.matcher(cmd);

        final StringBuffer sb = new StringBuffer(cmd.length());
        int lastMatchEnd = 0;
        while (m.find()) {
            sb.append(cmd.substring(lastMatchEnd, m.start()));
            final String envVar = m.group(1);
            final String envVal = System.getenv(envVar);
            if (envVal == null)
                sb.append(cmd.substring(m.start(), m.end()));
            else
                sb.append(envVal);
            lastMatchEnd = m.end();
        }
        sb.append(cmd.substring(lastMatchEnd));

        return sb.toString();
    }
Kevin Brock
Cheers - I suspect that this will be what I end up doing. I'm sure I'm not the first to try it. Perhaps I'm using the wrong terminology to search with. Thanks for the code too.
Tom Duckering
A: 

Just because I have the Windows environment variable resolution code in my clipboard (coded by yours truly) which works on a string, I'm just going to post it up here. It's perhaps the most efficient method (maybe regex is far less efficient, I'm not sure).

int from      = 0;
int startperc = -1;
int endperc   = -1;

while (true) {
    int index = tok.indexOf("%", from);
    if (index == -1) break;
    if (startperc == -1) {
        startperc = index;
    } else if (endperc == -1) {
        endperc = index;
    }
    from = index + 1;

    if (startperc >= 0 && endperc > startperc) {
        String startbit = tok.substring(0, startperc);
        String middlebit = System.getenv(tok.substring(startperc + 1, endperc));
        String endbit = endperc <= tok.length() ? tok.substring(endperc + 1) : ""; // substr up to end

        // integrate
        tok = startbit + middlebit + endbit;

        // reset
        startperc = -1;
        endperc   = -1;
    }
}
Chris Dennett