Chief A
Chief A

Reputation: 549

How to pass a string constant as it is in powershell

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?

Upvotes: 1

Views: 422

Answers (1)

mklement0
mklement0

Reputation: 440679

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).

Upvotes: 2

Related Questions