I have a Java program which I'm executing in a Linux environment through a bash script.
This is my simple bash script, which accepts a String.
#!/bin/bash
java -cp com.QuoteTester $1
The issue is that the command line argument can be with Spaces or Without spaces.
For example it can be either:
Apple Inc. 2013 Jul 05 395.00 Call
OR
Apple
My code is:
public static void main(String[] args)
{
String symbol = args[0];
if (symbol.trim().contains(" ")) // Option
{
}
else // Stock
{
}
}
So the issue is that , when I am trying to execute it this way:
./quotetester Apple Inc. 2013 Jul 05 395.00 Call
its only always going to the else condition that is Stock .
Is there anyway I can resolve this?
When you pass command line arguments with spaces, they are taken as space separated arguments, and are splitted on space. So, you don't actually have a single argument, but multiple arguments.
If you want to pass arguments with spaces, use quotes:
java classname "Apple Inc. 2013 Jul 05 395.00 Call"
This is not a Java issue per se. It's a shell issue, and applies to anything you invoke with such arguments. Your shell is splitting up the arguments and feeding them separately to the Java process.
You have to quote the arguments such that the shell doesn't split them up. e.g.
$ java -cp ... "Apple Inc. 2013"
etc.
See here for a longer discussion.
The arguments are handled by the shell , so any terminal settings should not affect this. You just need to have quoted argument and it should work.
Single quotes are the best option
Spaces and double quotes can be resolved this way.
java QuerySystem '((group = "infra") & (last-modified > "2 years ago"))'
In the original question the OP is using a shell script to call a java command line and would like the shell script to pass the arguments without performing the Blank interpretation (Word Splitting) option of input interpretation
https://rg1-teaching.mpi-inf.mpg.de/unixffb-ss98/quoting-guide.html#para:sh-ifs
If you know how many arguments there are then you can double quote the arguments
#!/bin/bash
java -cp com.QuoteTester "$1"
So you call this script, save as quotetester.sh.
./quotetester.sh "hello world"
and "hello world" gets passed as a single argument to Java. You could also use
./quotetester.sh hello\ world
with the same effect.
Related
I'm having difficulties to startup a java program from a shell script (bash) where nested variables are used
export MAIN_CLASS="xxxxx"
MAIN_CLASS_ARGS=("$FirstArg" "$SEC_ARG" )
CMD="java some args here ${MAIN_CLASS} ${MAIN_CLASS_ARGS[#]}"
exec $CMD
And I am passing parameter as
export FirstArg = hello
export SEC_ARG ="hi Jam"
But In my main java class I have getting 3 parameter hello, hi ,Jam. But I am expecting it to be only two. What I am missing here can anyone help me.
I have checked some of the link as
link
But not able to fix it.
When you run exec $CMD, then word splitting is performed on the contents of $CMD. It doesn't matter how the variable was built up; at this point, it's just a string which is split by the shell.
Since you appear to be using a shell with support for arrays, then one option would be to do this instead:
CMD=( java some args here "${MAIN_CLASS}" "${MAIN_CLASS_ARGS[#]}" )
exec "${CMD[#]}"
That is, build up an array of all the arguments, then use a quoted array expansion, which prevents word splitting from taking place.
I want some code in my program to run only if the user has input the character '*' at the command-line as a command-line argument. This is the code I've used:-
//myfile.java
import java.io.*;
public class myfile {
public static void main(String[] args) {
if(args[0].equals("*")){
//do stuff
System.out.println(args[0]);//added this line to see what exactly was being passed
}
}
}
When this program is executed at the command-line by entering:-
java myfile *
the output I'm expecting to see on the screen is the asterisk character, instead the output displayed is 'myfile.class'. Where am I going wrong? Why does Java change the asterisk to the .class file?
Also, note that the program worked perfectly the first four times I executed it and then started doing this!
Thanks in advance for your help.
Where am I going wrong?
The star character needs to be quoted or escaped. Run your java program like this:
java myfile "*"
or
java myfile \*
Why does Java change the asterisk to the .class file?
It doesn't. It is your shell that is doing it. It is shell file expansion ... or "globbing" as it is also called.
Run "ls *" or "echo *" and you will see that the same thing happens.
The command terminal already replaces the asterisk and java already gets the value that you see. I'd use any other character, that has no special meaning to the command terminal or otherwise you must escape the asterisk in your command.
Actually escaping arguments on Windows and especially in cmd.exe is non-trivial. This nice article explains it in detail: Everyone quotes command line arguments the wrong way :
the takaway for your case is: surround the asterisk with quotes.
Answer to your question in the comment:
Using the escape character worked! But I still don't get why it worked without the escape character the first few times
I am not sure, but maybe you run into this behavior: It makes a difference if the pattern can be expanded or not. For example, when I pass Test* as argument, then there are 2 cases to consider:
in the current folder there is a file called Test1.txt: then your java program will get Test1.txt as argument
when there are no matching files, your program will get Test* as argument
However, I am not sure, how this would apply to your case, since you only pass *: that should only work in an empty directory.
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 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?
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.