1

I have the following simple java program:

import java.util.Arrays;
public class Arguments
{
    public static void main(String [] args)
    {
        System.out.println("args: "+Arrays.toString(args));
    }
}  

When I execute this in powershell using the following command: java Arguments "*.java" the string received in the program is not "*.java" but a comma-separated list of all java files in the current directory. And if there are no java files in the current directory the string received is "*.java".

I want to know why this is happening and how to pass a string as it is without converting it.

Update: java Arguments '"*".java' and java Arguments `"*.java`" did the work but this creates the same problem when executed in cmd. Can anyone explain why this is happening? Is there any common solution for both PowerShell and cmd?

Chief A
  • 320
  • 5
  • 19
  • This sounds like `java.exe` globbing the files, can you try with `'*.java'` instead (single-quotes) – Mathias R. Jessen Apr 18 '19 at 14:48
  • still the same with '*.java' – Chief A Apr 18 '19 at 14:51
  • you should run a jar file using -jar option. something like this: `java -jar Arguments "*.java"` – Amin Heydari Alashti Apr 18 '19 at 14:55
  • @epcpu cant the program run without creating a jar file? I tried making one and executed it .but its giving me `Unable to access jarfile Arguments` error – Chief A Apr 18 '19 at 15:02
  • 1
    Have you tried to escape the quotes with a grave-accent (add grave-accents directly before each of the double quotes)? – DBADon Apr 18 '19 at 15:06
  • @DBADon yes backticking the double quotes ie, \`"*.java\`" also works.thanks.but then the string is passed as `\`*.java\`` in cmd not `*.java` – Chief A Apr 18 '19 at 15:31
  • @MathiasR.Jessen: Indeed it is `java.exe` that performs the globbing, but `'*.java'` won't help that; PowerShell passes both `'*.java'` and `"*.java"` as `*.java` (no quotes) to external programs; only something like `'"*.java"'` would work (on Windows). – mklement0 Apr 19 '19 at 16:05

1 Answers1

2

It is not PowerShell (nor cmd.exe) that interprets "*.java" as a filename pattern and expands (resolves) it to the matching files, known as globbing in the Unix world.

(You would only get that behavior if you used *.java - i.e., no quoting - in PowerShell Core on Unix-like platforms, but never with a quoted string such as "*.java" or '*.java', and even without quoting never on Windows).

Apparently, it is legacy versions of java.exe on Windows that automatically perform the globbing on unquoted arguments, in an apparent attempt to emulate the behavior of POSIX-like shells such as Bash on Unix.

  • As of (at least) JDK 12, this behavior no longer seems to be effect, at least not by default.

  • The linked answer suggests that in earlier versions there may be a system property that controls the behavior, but it's unclear what its name is.

    • Generally, the syntax java -D<systemPropName>=<value> ... can be used to set a system property on startup.

Therefore, you have the following options:

  • Upgrade to a Java version that no longer exhibits this behavior (by default).

  • In legacy versions, find the relevant system property name that disables the behavior and use the syntax shown above.

  • Use shell-specific quoting, as shown below.


Using quoting to prevent globbing:

To prevent java.exe from performing globbing, the invocation command line must ultimately contain "*.java", i.e., the argument must be enclosed in double quotes.

Unfortunately, there is no common syntax that works in both PowerShell and cmd.exe:

cmd.exe:

cmd.exe passes double-quoted arguments through as-is, so the following is sufficient:

java Arguments "*.java"

PowerShell:

PowerShell, by contrast, performs re-quoting as needed behind the scenes (see this answer for more information).

Since an argument with content *.java normally does not require quoting when you pass it to an external program, PowerShell translates both "*.java" and '*.java' to unquoted *.java in the command line that is ultimately used behind the scenes - which is what you experienced.

There are two ways around that:

  • Use java Arguments '"*.java"', i.e., embed the " chars. in the argument, inside a literal string ('...').

  • Use java Arguments --% "*.java"; --% is the stop-parsing symbol (PSv3+), which instructs PowerShell to pass the remainder of the command line through as-is (except for expanding cmd.exe-style environment-variable references).

mklement0
  • 245,023
  • 45
  • 419
  • 492