java reads "*" in args[0] as the .class file - java

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.

Related

Absolute path with string variable

PLEASE help me to understand what is going on here:
my code:
import java.io.File;
public class Main {
public static void main(String[] args) {
String name = "‪d:\\downloads\\testfile.mp3";
File file1 = new File(name);
System.out.println(file1.getAbsolutePath());
File file = new File("d:\\downloads\\testfile.mp3");
System.out.println(file.getAbsolutePath());
}
}
The output:
J:\Louw\Programming\PathTest\‪d:\downloads\testfile.mp3
d:\downloads\testfile.mp3
Question:
Why would the String variable produce a different Absolutepath than typing the string directly with new File object? (Obviously the first output also throws a "FileNotFound" exception if trying to use later).
my Eclipse java development environment is:
Eclipse Java EE IDE for Web Developers.
Version: Neon.2 Release (4.6.2)
Build id: 20161208-0600
Please assist.
Now I am not 100 % sure whether this is the correct explanation, but I believe it is consistent, so I also believe that it is worth for you to check.
When I copy your code into my Eclipse, your string name begins with a character with Unicode value 8234 (202A hexadecimal). This character is not printed, so the two strings look the same, but they are not. The mentioned character is not it the string that you pass when constructing the second File object. On fileformat.info the character is called “left-to-right embedding”, I don’t know what this means.
It would make sense that such a character in front of d:\\ would cause Java not to recognize the string as an absolute path name and therefore take it as a relative one, relative to your working directory.
It remains to be determined whether that character is in your source file too or only has crept in on Stack Overflow or in my copy-paste operation.
If the 8234 is indeed the culprit: in my Eclipse I can delete it with backspace as any other character, and everything works as expected. Failing that, you can always delete a sequence of characters containing at least the " before and the d after and type them again.
Where that char may come from, I have no good idea. It sounds unlikely that you should have typed Alt-202A on your keyboard without knowing you had done so.
Your code is fine, and is doing what you expect. It's printing ‪d:\downloads\testfile.mp3 twice.
Either something in how you execute your program is printing J:\Louw\Programming\PathTest\ with no newline to stdout before running your program, or you're seeing the system prompt and interpreting it as output.
You have a strange non-printable Unicode character at the start of your name String. The second instance of the string looks the same, but doesn't include that character. Paste the second string over the top of your first string and the problem will go away.

Could someone look at my code and tell me what's wrong?

I am trying to get this simple program to work but I'm not sure what I'm doing wrong; I tried making a new file to see if the problem was with my syntax but it's still happening. Here it is:
public class test {
public static void main(String[] args) {
String operator = args[0];
switch(operator) {
case "*":
System.out.println("Hello");
break;
}
}
}
I'm trying to run this program on my terminal by first doing
$ javac test.java
and then actually running the program along with the argument
$ java test *
and I get nothing after that, any reason why? It seems to work when "*" is replaced with "+".
I also noticed that it would only work if I typed out
$ java test "*" //notice the quotation marks
Why does the asterisk without the parenthesis not work even though it is a string but "+" without the parenthesis works? Is there something I am missing?
The problem is nothing to do with Java. The problem happens because the shell will treat the * character as a filename pattern and expand it to the names of all files in the current directory.
The solution is to escape the * character on the command line. There is nothing that you can do in Java to solve this.
There are a three ways that will work as escaping (for a POSIX compliant shell)
java test "*"
java test '*'
java test \*
There may be other obscure ways to do this .... but the above should suffice.
(The difference between "*" and '*' is that they escape different shell constructs. Double quotes disable just "globbing" of file pathnames. Single quotes also disable parameter substitution and other things.)
Characters that may be need to be escaped if you use them in command line arguments include:
*, ?, [, ], ~, {, } - used in globbing, etc
$ - parameter substitution
shell symbols |, &, ;
# - the comment character
the backquote character.
You should refer to a tutorial or textboox on the shell, or read the manual entry for the shell you are using.

Java command line argument containing backslash

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

Why doesn't * as a command line parameter to "java" work as expected?

I have a program that takes in a string as parameter and the searches the string in a text file.
Everything works perfectly except when I enter * as the parameter. It prints out all the file name in my directory. Seems it doesn't go through the code when I enter * as the parameter.
Anyone know whats going on?
You are most likely passing a glob of files from the command line. This link might be of interest:
http://en.wikipedia.org/wiki/Glob_(programming)#Syntax
Basically, when you say
java ... *
The * character is expanded (by your shell) into a list of files in the current directory. This happens before java even sees the * character, and java instead sees "file1 file2 ...".
It may help to surround the * character with single quotes on the command line, like this:
'*'
or by escaping it:
\*
Your shell is expanding the * before it gets to your program. Try escaping it like so
bash$ java MyClass \*
- * has a special meaning in Regular expressions.
- So you must use \\ before it.
Eg:
\\*

The issue of * in Command line argument

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.

Categories