I run egrep using Java Runtime.exec()
String command = "egrep \'(Success|Loading\\.\\.\\.|Loaded : READY|Found a running instance)\' "+ instance.getPath() + "/log";
Runtime.getRuntime().exec(command);
The stdout is always null and stderr shows "egrep: Unmatched ( or (". but when I copy the command to shell and run, it returns the correct value.
The solution is pretty simple: (Success|Loading\\.\\.\\.|Loaded is not a valid regex.
You can't protect white space with quotes when using Process.exec(String). Always use the versions of exec() that take an array or, even better, use ProcessBuilder.
That way, you can pass each argument as a single Java String and spaces and other special characters won't create any problems.
The single quotes should not be escaped. You don't escape them on the command line, either, do you?
Related
I need to use Java to rsync several files using one command
the following command works fine in shell
rsync -avrz --timeout=100 rsync://10.149.21.211:8730/'logflow/click/file1 logflow/click/file2' /home/kerrycai/puller"
but when i use the following Java code , it does not work
String cmd = "rsync -avrz --timeout=100 rsync://10.149.21.211:8730/'logflow/click/file1 logflow/click/file2' /home/kerrycai/puller";
Process p = Runtime.getRuntime().exec(cmd);
int ret = p.waitFor();
the ret value is not equal to 0 (5 in my test), and the command is not executed succeed, after some debugging , it seem the problem is caused by the single quote
So, my questions is
Can I using java to execute a shell command which has single quote in it (Pls note, the single quote is in the middle of a parameter, not start/end) ?
Can I have a shell command to rsync several files in one command , and the command does not have single(double) quotes in it ?
Note to #Chris: this combination of multiple filenames (really modified-partly-like-filenames) in one argument is indeed very unusual and even 'suspicious' for Unix in general, but is (or at least was) correct for rsync in particular.
Preface: Java Runtime.exec does NOT 'execute a shell command' (unless you explicitly run a shell and give it a command); it runs a program, with arguments. These different things are often confused because most of the shell commands used by normal users are commands to run programs, but this is one case where the difference matters. In particular quoting a space to shell causes the shell to pass a single argument to the program containing the space instead of splitting into two (or more) arguments, but the quote itself is NOT included in the argument.
First you should look at the man page (on your system or online at https://download.samba.org/pub/rsync/rsync.html) under ADVANCED USAGE. Current (and IME even moderately old) versions of rsync have a more convenient syntax with separate arguments to get multiple files, which the simple parsing used by Runtime.exec(String) can handle like this:
rsync -avrz --timeout=100 --port=8730 10.149.21.211::logflow/click/file1 ::logflow/click/file2 /home/kerrycai/puller
But if you need (or really want) to use the quoted-space form then you need to do the tokenization yourself and use the String[] overload as suggested by #EJP -- although you can still use Runtime, you don't need ProcessBuilder for this. Specifically do something along the lines of:
String[] cmdarray = {"rsync",
"-avrz",
"--timeout=100",
"rsync://10.149.21.211:8730/logflow/click/file1 logfile/click/file2",
// separated argument contains space but not single (or other) quote
"/home/kerrycai/puller" };
... Runtime.getRuntime.exec(cmdarray); ...
You're calling a somewhat large command from Java. Why not just use a shell script? Put your gnarly command in myScript.sh and then have Java invoke /bin/bash myScript.sh. Makes all the weirdness to do with string handling in Java go away.
I want to run something similar to the following:
java MyProgram C:\Path\To\My\File
When I do this and output the contents of the first argument, it outputs:
C:PathToMyFile
This works, however:
java MyProgram "C:\Path\To\My\File"
But I want to be able to do the first command instead of the second. How can I achieve this?
The \ charecter is used to "escape" special characters. This means it tells the program to ignore them, or not do anything special to them. To make this work just use \\ instead of \. This escapes the \. So use
C:\\Path\\To\\My\\File
I have a .sh script with a property=value. Let it be:
some_property="some value"
The value of the property is used along the script and script is launched in Java code. I want to dynamically change this property's value. I tried to use replaceFirst() method, but I don't know the actual value of "some_property" to replace it correctly using regexp.
How can I edit a .sh file with replacing a single line that starts with "some_property=" by some_property=my_value? By the way there're several places in a file where pattern "some_property=" can be met, so I need to change the first occurrence.
You should be fine with a regex:
line.replaceFirst("some_property=.*$", "some_property=\"" + your_value + "\"");
You can get position of the = and \n using String.indexOf(int) and then replace the string between = and \n using, for example, replace(CharSequence, CharSequence).
Btw - some_property=(.+) (and replacing $1) wouldn't be okay? :)
One of the arguments passed to my java program is like this, ab|cd. Initially, when I run the java program, like this,
$ java className ab|cd
it fails, since | is interpreted in the linux shell as a pipe symbol. So only ab is passed into java program. So I made a second attempt:
$ java className "ab|cd"
This time, "ab|cd" is passed in, but the value includes the double quotes. What the program is really intended to have is ab|cd. How can I pass in the correct value without the quotes?
In the command shell, you can escape out characters using the '\' character.
java className ab\|cd
Try (for Linux):
$ java className ab\|cd
For Windows:
java className ab^|cd
Try this,
"\" is used inorder to nullify the effect of the characters which have special meanings.
java className ab\|cd
Maybe try this:
arg="ab|cd"
java className $arg
I wrote a program in Java that accepts input via command line arguments.
I get an input of two numbers and an operator from the command line.
To multiply two numbers, I have to give input as e.g. 5 3 *, but it's not working as written.
Why is it not accepting * from the command line?
That's because * is a shell wildcard: it has a special meaning to the shell, which expands it before passing it on to the command (in this case, java).
Since you need a literal *, you need to escape it from the shell. The exact way of escaping varies depending on your shell, but you can try:
java ProgramName 5 3 "*"
Or:
java ProgramName 5 3 \*
By the way, if you want to know what the shell does with the *, try printing the content of String[] args to your main method. You'll find that it will contain names of the files in your directory.
This can be handy if you need to pass some filenames as command line arguments.
See also
Wikipedia: glob
For example, if a directory contains two files, a.log and b.log then the command cat *.log will be expanded by the shell to cat a.log b.log
Wikipedia: Escape character
In Bourne shell (sh), the asterisk (*) and question mark (?) characters are wildcard characters expanded via globbing. Without a preceding escape character, an * will expand to the names of all files in the working directory that don't start with a period if and only if there are such files, otherwise * remains unexpanded. So to refer to a file literally called "*", the shell must be told not to interpret it in this way, by preceding it with a backslash (\).
Under MS WINDOWS not quite true: "java.exe" silently expands command line arguments with the wildcards
*
?
[abc]
, but only in the last component, so
a/*/*
does not work as you may expect.
It also ignores the entries "." and "..", but does honor other file names starting with ".".
To avoid misunderstandings: If I look at the command line of the running JAVA process with PROCEXP, I see the unexpanded args!
I found no way to work around this. In other words: As long as you have at least one file or directory in the current directory, "java Calc 3 * 7" will NOT work!
This is VERY ugly, and seems to always having been there in all JRE versions up to and including Java 8.
Does anybody have an idea how to disable Java's nasty command line expansion?
* has special meaning in shell interpreters. How to get a * literally is depending on what shell interpreter you are using. For Bash, you should put single quotes around the *, i.e. '*', instead of double quotes like "*".
Try surrounding the * with quotes like "*". The star is a reserved symbol on the command line.
Use single quotes:
java FooBar 5 3 '*'
This works with most of the popular shells (including bash and ksh).
Expanding on #Arno Unkrig's answer:
On Windows, some JVMs definitely do expand the "*" character, and it is not the shell expanding the path. You can confirm this by writing a small Java program that prints out the arguments:
public class TestArgs {
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
System.out.println("Arg " + i + ": " + args[i]);
}
}
}
The good news is, there is a workaround! You can use #filename as an argument to JVM like this:
java #args.txt where args.txt is a text file that contains the arguments for each line. Example content:
TestArgs
*
This is equivalent to calling java with two arguments TestArgs and *. Most importantly, * is not expanded when it is included using the #filename method. I was able to find the details from this page.