Evaluation of environment variables in command run by Java's Runtime.exec() - java

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

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

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

The regex
[$]\\{(\\S+)\\}
is greedy (S+) and in case of xx ${a} xx ${b} xx it will match A} xx ${B instead of seperately A and B. Did you ever test it with multiple vars in the cmd?
So if there are multiple variables to be replaced. It should be
[$]\\{(\\S+?)\\}

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

Related

Is there a way to categorize code so that I can minimize something and use a comment to write what it does for organization?

This is a bit unorthodox and also I am relatively new to coding but here is what I want to do:
I am trying to make a flashcard simulator (like quizlet) to practice coding, and I have so far successfully made a program that takes a text file with terms and definitions and converts it into two arrays (terms and definitions).
Now this is taking up a lot of space for me looking at it, and I notice you can minimize certain loops and things so it just shows the top line, to reduce clutter. So I want to minimize the whole function for looking at and just write a comment next to it saying what it does, so its like a line of code.
The problem is any redundant loops (like a for loop that executes once) make the arrays unusable outside of that loop. So any ideas if I want to do this?
My best idea is a method but since I am a beginner I don't entirely know how to do that yet and my impression is that it would be outside of the main method and separate from the code which is not what I want cause I only use it once.
Thanks,
This is my code if you want it:
BufferedReader reader = new BufferedReader(new FileReader("Flashcards.txt"));
String[] terms = new String[128];
String[] defs = new String[128];
String term;
String def;
String line;
byte c = 0;
while((line = reader.readLine()) != null) {
boolean after = false;
def = "";
term = "";
for (short i = 0; i < line.length(); i++) {
if (line.charAt(i) == ':')
after = true;
else if (!after)
term = term + line.charAt(i);
else
def = def + line.charAt(i);
}
terms[c] = term;
defs[c]= def.strip();
c++;
In my personal opinion, a method isn't a bad idea, even if you are only going to use it once. A method would allow you to move all your code outside your main method and reduce it to one line of code, collapse it outside of the main method, and make your code more maintainable in the future. Editors like Eclipse (I don't know about Netbeans or InteliJ) do not allow you to collapse your code in the way that you want.

Using the split function in a proper way

I'm trying to understand what is the proper way to achieve the following goal. Consider the following string:
/some/path/to/some/dir
I would like to split the path by / and get the last two string and connect them with _ so the output would be:
some_dir
I'm familiar with the split function but I'm not sure what is the proper way to write this code when speaking of code-styling.
I know that I have to check first if the string is valid. For example, the string dir is not valid.
What is the proper way to solve it?
You can play with the following. I omit error checks for the sake of simplicity.
class Test {
public static void main(String[] args) {
String s = "/some/path/to/some/dir";
String[] parts = s.split("/");
int len = parts.length;
String theLastTwoParts = parts[len - 2] + "_" + parts[len - 1];
System.out.println(theLastTwoParts);
}
}
You can use the below shown function for this purpose:
public String convertPath(String path) {
String[] str = path.split("/");
int length = str.length;
if(length < 2) {
//Customize the result here for this specific case
return "";
}
return str[length-2] + "_" + str[length-1];
}
If you're actually handling paths, you probably want to use the standard library's Path ecosystem. You can use it by
Path path = Paths.get(p);
int nameCount = path.getNameCount();
if (nameCount < 2) throw new RuntimeException();
String result = String.format("%s_%s", path.getName(nameCount-2), path.getName(nameCount-1));
See it here.
The advantage is that when you're working on Windows, it will also handle the different path separator, so it's more platform independent.
The question of "dir" being "invalid" raises the follow-up question of how you want it handled. Throwing a RuntimeException like I do is probably not going to hold up.

Java String Analysis for complete string regular expression

I am looking for a tool like Java String Analysis (JSA) that could sum up a string as a regex. I have tried to do that with JSA, but there I need to search for a specific method like StringBuffer.append or other string operations.
I have strings like that:
StringBuilder test=new StringBuilder("hello ");
boolean codition=false;
if(codition){
test.append("world");
}
else{
test.append("other world");
}
test.append(" so far");
for(int i=0;i<args.length;i++){
test.append(" again hello");
}
// regularExpression = "hello (world| other world) so far( again hello)*"
And my JSA implementation looks like that so far:
public static void main(String[] args) {
StringAnalysis.addDirectoryToClassPath("bootstrap.jar");
StringAnalysis.loadClass("org.apache.catalina.loader.Extension");
List<ValueBox> list = StringAnalysis.getArgumentExpressions("<java.lang.StringBuffer: java.lang.StringBuffer append(java.lang.String)>", 0);
StringAnalysis sa = new StringAnalysis(list);
for (ValueBox e : list) {
Automaton a = sa.getAutomaton(e);
if (a.isFinite()) {
Iterator<String> si = a.getFiniteStrings().iterator();
StringBuilder sb = new StringBuilder();
while (si.hasNext()) {
sb.append((String) si.next());
}
System.out.println(sb.toString());
} else if (a.complement().isEmpty()) {
System.out.println(e.getValue());
} else {
System.out.println("common prefix:" + a.getCommonPrefix());
}
}
}
I would be very appreciated for any help with the JSA tool or for a hint to another tool. My biggest issue with the regex the control flow structure around the string constant.
I'm not aware of a tool which yields you a regex out of the box.
But since you have issues with the CFG I would recommend you to write a static analysis tailored to your problem. You could use a static analysis/bytecode framework like OPAL (Scala) or Soot (Java). You will find tutorials on each project page.
Once you set it up you can load the target jar. You should be able to leverage the control flow of the program then like in the following example:
1 public static void example(String unknown) {
2 String source = "hello";
3 if(Math.random() * 20 > 5){
4 source += "world";
5 } else {
6 source += "unknown";
7 }
8 source += unknown;
}
If your analysis finds a String or StringBuilder which is initialized you can start to build your regular expression. Line number two for instance would bring your regex to "hello". If you meet a conditional in the control flow of your program you can analyze each path and combine them via an "|" later on.
Then branch: "world" (line 4)
Else branch: "unknown" (line 6)
This could be summarized at line 7 to (world)|(unknown) and append to the regex before the conditional.
If you encounter a variable you either can trace it back if you do an inter-procedural analysis or you have to use the wildcard operator ".*" otherwise.
Final regex: "hello((world)|(unknown)).*"
I hope that this leads you to your solution you want to achieve.
Apache Lucene has some tools around finite state automata and regular expressions. In particular, you can take the union of automata, so I'd guess you can easily build an automaton accepting a finite number of words.

Replace the first letter of a String in Java?

I'm trying to convert the first letter of a string to lowercase.
value.substring(0,1).toLowerCase() + value.substring(1)
This works, but are there any better ways to do this?
I could use a replace function, but Java's replace doesn't accept an index. You have to pass the actual character/substring. It could be done like this:
value.replaceFirst(value.charAt(0), value.charAt(0).toLowerCase())
Except that replaceFirst expects 2 strings, so the value.charAt(0)s would probably need to be replaced with value.substring(0,1).
Is there any standard way to replace the first letter of a String?
I would suggest you to take a look at Commons-Lang library from Apache. They have a class
StringUtils
which allows you to do a lot of tasks with Strings. In your case just use
StringUtils.uncapitalize( value )
read here about uncapitalize as well as about other functionality of the class suggested
Added: my experience tells that Coomon-Lang is quite good optimized, so if want to know what is better from algorithmistic point of view, you could take a look at its source from Apache.
The downside of the code you used (and I've used in similar situations) is that it seems a bit clunky and in theory generates at least two temporary strings that are immediately thrown away. There's also the issue of what happens if your string is fewer than two characters long.
The upside is that you don't reference those temporary strings outside the expression (leaving it open to optimization by the bytecode compiler or the JIT optimizer) and your intent is clear to any future code maintainer.
Barring your needing to do several million of these any given second and detecting a noticeable performance issue doing so, I wouldn't worry about performance and would prefer clarity. I'd also bury it off in a utility class somewhere. :-) See also jambjo's response to another answer pointing out that there's an important difference between String#toLowerCase and Character.toLowerCase. (Edit: The answer and therefore comment have been removed. Basically, there's a big difference related to locales and Unicode and the docs recommend using String#toLowerCase, not Character.toLowerCase; more here.)
Edit Because I'm in a weird mood, I thought I'd see if there was a measureable difference in performance in a simple test. There is. It could be because of the locale difference (e.g., apples vs. oranges):
public class Uncap
{
public static final void main(String[] params)
{
String s;
String s2;
long start;
long end;
int counter;
// Warm up
s = "Testing";
start = System.currentTimeMillis();
for (counter = 1000000; counter > 0; --counter)
{
s2 = uncap1(s);
s2 = uncap2(s);
s2 = uncap3(s);
}
// Test v2
start = System.currentTimeMillis();
for (counter = 1000000; counter > 0; --counter)
{
s2 = uncap2(s);
}
end = System.currentTimeMillis();
System.out.println("2: " + (end - start));
// Test v1
start = System.currentTimeMillis();
for (counter = 1000000; counter > 0; --counter)
{
s2 = uncap1(s);
}
end = System.currentTimeMillis();
System.out.println("1: " + (end - start));
// Test v3
start = System.currentTimeMillis();
for (counter = 1000000; counter > 0; --counter)
{
s2 = uncap3(s);
}
end = System.currentTimeMillis();
System.out.println("3: " + (end - start));
System.exit(0);
}
// The simple, direct version; also allows the library to handle
// locales and Unicode correctly
private static final String uncap1(String s)
{
return s.substring(0,1).toLowerCase() + s.substring(1);
}
// This will *not* handle locales and unicode correctly
private static final String uncap2(String s)
{
return Character.toLowerCase(s.charAt(0)) + s.substring(1);
}
// This will *not* handle locales and unicode correctly
private static final String uncap3(String s)
{
StringBuffer sb;
sb = new StringBuffer(s);
sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
return sb.toString();
}
}
I mixed up the order in various tests (moving them around and recompiling) to avoid issues of ramp-up time (and tried to force some initially anyway). Very unscientific, but uncap1 was consistently slower than uncap2 and uncap3 by about 40%. Not that it matters, we're talking a difference of 400ms across a million iterations on an Intel Atom processor. :-)
So: I'd go with your simple, straightforward code, wrapped up in a utility function.
Watch out for any of the character functions in strings. Because of unicode, it is not always a 1 to 1 mapping. Stick to string based methods unless char is really what you want. As others have suggested, there are string utils out there, but even if you don't want to use them for your project, just make one yourself as you work. The worst thing you can do is to make a special function for lowercase and hide it in a class and then use the same code slightly differently in 12 different places. Put it somewhere it can easily be shared.
Use StringBuffer:
buffer.setCharAt(0, Character.toLowerCase(buffer.charAt(0)));

String capitalize - better way

What method of capitalizing is better?
mine:
char[] charArray = string.toCharArray();
charArray[0] = Character.toUpperCase(charArray[0]);
return new String(charArray);
or
commons lang - StringUtils.capitalize:
return new StringBuffer(strLen)
.append(Character.toTitleCase(str.charAt(0)))
.append(str.substring(1))
.toString();
I think mine is better, but i would rather ask.
I guess your version will be a little bit more performant, since it does not allocate as many temporary String objects.
I'd go for this (assuming the string is not empty):
StringBuilder strBuilder = new StringBuilder(string);
strBuilder.setCharAt(0, Character.toUpperCase(strBuilder.charAt(0))));
return strBuilder.toString();
However, note that they are not equivalent in that one uses toUpperCase() and the other uses toTitleCase().
From a forum post:
Titlecase <> uppercase
Unicode
defines three kinds of case mapping:
lowercase, uppercase, and titlecase.
The difference between uppercasing and
titlecasing a character or character
sequence can be seen in compound
characters (that is, a single
character that represents a compount
of two characters).
For example, in Unicode, character
U+01F3 is LATIN SMALL LETTER DZ. (Let
us write this compound character
using ASCII as "dz".) This character
uppercases to character U+01F1, LATIN
CAPITAL LETTER DZ. (Which is
basically "DZ".) But it titlecases to
to character U+01F2, LATIN CAPITAL
LETTER D WITH SMALL LETTER Z. (Which
we can write "Dz".)
character uppercase titlecase
--------- --------- ---------
dz DZ Dz
If I were to write a library, I'd try to make sure I got my Unicode right beofre worrying about performance. Off the top of my head:
int len = str.length();
if (len == 0) {
return str;
}
int head = Character.toUpperCase(str.codePointAt(0));
String tail = str.substring(str.offsetByCodePoints(0, 1));
return new String(new int[] { head }).concat(tail);
(I'd probably also look up the difference between title and upper case before I committed.)
Performance is equal.
Your code copies the char[] calling string.toCharArray() and new String(charArray).
The apache code on buffer.append(str.substring(1)) and buffer.toString(). The apache code has an extra string instance that has the base char[1,length] content. But this will not be copied when the instance String is created.
StringBuffer is declared to be thread safe, so it might be less effective to use it (but one shouldn't bet on it before actually doing some practical tests).
StringBuilder (from Java 5 onwards) is faster than StringBuffer if you don't need it to be thread safe but as others have said you need to test if this is better than your solution in your case.
Have you timed both?
Honestly, they're equivalent.. so the one that performs better for you is the better one :)
Not sure what the difference between toUpperCase and toTitleCase is, but it looks as if your solution requires one less instantiation of the String class, while the commons lang implementation requires two (substring and toString create new Strings I assume, since String is immutable).
Whether that's "better" (I guess you mean faster) I don't know. Why don't you profile both solutions?
look at this question titlecase-conversion . apache FTW.
/**
* capitalize the first letter of a string
*
* #param String
* #return String
* */
public static String capitalizeFirst(String s) {
if (s == null || s.length() == 0) {
return "";
}
char first = s.charAt(0);
if (Character.isUpperCase(first)) {
return s;
} else {
return Character.toUpperCase(first) + s.substring(1);
}
}
If you only capitalize limited words, you better cache it.
#Test
public void testCase()
{
String all = "At its base, a shell is simply a macro processor that executes commands. The term macro processor means functionality where text and symbols are expanded to create larger expressions.\n" +
"\n" +
"A Unix shell is both a command interpreter and a programming language. As a command interpreter, the shell provides the user interface to the rich set of GNU utilities. The programming language features allow these utilities to be combined. Files containing commands can be created, and become commands themselves. These new commands have the same status as system commands in directories such as /bin, allowing users or groups to establish custom environments to automate their common tasks.\n" +
"\n" +
"Shells may be used interactively or non-interactively. In interactive mode, they accept input typed from the keyboard. When executing non-interactively, shells execute commands read from a file.\n" +
"\n" +
"A shell allows execution of GNU commands, both synchronously and asynchronously. The shell waits for synchronous commands to complete before accepting more input; asynchronous commands continue to execute in parallel with the shell while it reads and executes additional commands. The redirection constructs permit fine-grained control of the input and output of those commands. Moreover, the shell allows control over the contents of commands’ environments.\n" +
"\n" +
"Shells also provide a small set of built-in commands (builtins) implementing functionality impossible or inconvenient to obtain via separate utilities. For example, cd, break, continue, and exec cannot be implemented outside of the shell because they directly manipulate the shell itself. The history, getopts, kill, or pwd builtins, among others, could be implemented in separate utilities, but they are more convenient to use as builtin commands. All of the shell builtins are described in subsequent sections.\n" +
"\n" +
"While executing commands is essential, most of the power (and complexity) of shells is due to their embedded programming languages. Like any high-level language, the shell provides variables, flow control constructs, quoting, and functions.\n" +
"\n" +
"Shells offer features geared specifically for interactive use rather than to augment the programming language. These interactive features include job control, command line editing, command history and aliases. Each of these features is described in this manual.";
String[] split = all.split("[\\W]");
// 10000000
// upper Used 606
// hash Used 114
// 100000000
// upper Used 5765
// hash Used 1101
HashMap<String, String> cache = Maps.newHashMap();
long start = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++)
{
String upper = split[i % split.length].toUpperCase();
// String s = split[i % split.length];
// String upper = cache.get(s);
// if (upper == null)
// {
// cache.put(s, upper = s.toUpperCase());
//
// }
}
System.out.println("Used " + (System.currentTimeMillis() - start));
}
The text is picked from here.
Currently, I need to upper case the table name and columns, many many more times, but they are limited.Use the hashMap to cache will be better.
:-)
use this method for capitalizing of string. its totally working without any bug
public String capitalizeString(String value)
{
String string = value;
String capitalizedString = "";
System.out.println(string);
for(int i = 0; i < string.length(); i++)
{
char ch = string.charAt(i);
if(i == 0 || string.charAt(i-1)==' ')
ch = Character.toUpperCase(ch);
capitalizedString += ch;
}
return capitalizedString;
}

Categories