How to use command-line argument files for javac on windows? - powershell

Here's my working directory:
C:\GitHub\
And under this directory I have:
class\ src\ cmain
and cmain is my argument file.
All my .java source code files are undersrc\
main.java CalcHandler.java
And here's the content ofcmain
-cp .\class\
-sourcepath .\src\
-d .\class\
.\src\main.java
But when I tried compiling src\main.java in PowerShell usingcmain, it is not recognized:
PS C:\GitHub> javac #cmain
Usage: javac <options> <source files>
where possible options include:
-g Generate all debugging info
-g:none Generate no debugging info
....
I tried this in Linux and it worked fine, contents were exactly the same.
What should I do to make it work?
Edit: Apparently this is PowerShell's fault, it worked in command-prompt. But still I'd like to hear from you about how to make it correct in PowerShell.

javac '#cmain'
PowerShell parses arguments to commands, and #cmain means taking the array $cmain and expanding it to one argument per item (splatting). By passing an explicit string you can bypass that automatism.
Other options:
javac --% #cmain
This will tell PowerShell to stop parsing arguments after the --% marker and just pass them verbatim to the other program.
javac `#cmain
This will escape the # so its special behavior will not apply.
Always remember that shell features will need workarounds if you want to pass that syntax to other programs. That's no different than % expanding environment variables in cmd, or most shells tokenizing arguments at spaces and other whitespace. A small utility program that just prints its arguments can come in handy for diagnosing such cases.

Related

code --diff fails when filename contains an ampersand '&'

I am experiencing a rather puzzling error while trying to perform a diff on two files using Visual Studio Code from the command line. I have a text file in the cloud where I save some work related notes. I need to resolve conflicts with other clients editing the file. Usually this only happens during a loss of connection though somehow I find myself having to resolve a lot of them so between this and other uses of diff I will use the usual syntax. It looks something like this:
code --diff "R&D (cloud conflict 2-5-23).txt" "R&D.txt"
My filename happens to have a '&' in it and this command launches the usual 2-way diff in VS Code and reads through the first file name with no problem but doesn't read past the second '&' and the resulting diff tab in VS Code looks something like:
R&D (cloud conflict 2-25-23).txt <-> R
Where the right side "R" doesn't exist. So it would seem '&' needs to be processed literally.
No problem, let's see if backslash \ is an accepted escape parameter...
code --diff "R\&D (cloud conflict 2-5-23).txt" "R\&D.txt"
Nope. Same problem. 🤔 In fact this outputs something even stranger:
Code diff tab:
&D (cloud conflict 2-25-23).txt <-> R
with shell output:
'D.txt' is not recognized as an internal or external command, operable program or batch file.
I also tried the carrot symbol '^' as an escape parameter to a similar effect. I just includes it in the first file and the editor still thinks the second file name is just "R".
The help file for the VS Code command line integration didn't have a lot to say about the --diff parameter other than a short description and I was hoping to get something about processing strings literally or escape characters. Perhaps another parameter that I need or maybe this has more to do with the shell in general.
I find it really strange that it can read the first full file name but breaks at the second '&'. Weirder still that if a supposed escape character is included in the second file name, it will omit that as well. 😵
For now all I can do is rename the file which is a bummer. 🤷‍♂️ I have VS Code version 1.75.0 on Windows 10 Home latest version/build and I'm using PowerShell version 5.1.19041.2364.
Edit: The issue definitely appears to be PowerShell related as it turns out. I was finally able to run this command successfully in a regular command prompt. (Simply typing "cmd" and Enter into the PowerShell window before running the diff command). Unfortunately, I happen to be running this command as part of PowerShell script. I may have to figure out how to run a CMD command from inside my PowerShell script if that is at all possible. I'm not sure. 🤔 If not, I need to figure out what exactly PowerShell is doing to my command when it reaches the '&' character.
tl;dr
You need a workaround:
cmd /c 'code --diff "R&D (cloud conflict 2-5-23).txt" "R&D.txt"'
Alternatively, using --%, the stop-parsing token:
code --diff "R&D (cloud conflict 2-5-23).txt" --% "R&D.txt"
Note: --% comes with fundamental limitations, notably the inability to reference PowerShell variables - see this answer.
Background information:
The root cause is that code is implemented as a batch file (code.cmd) and that cmd.exe, the interpreter that executes batch file inappropriately parses its list of arguments as if they had been submitted from INSIDE a cmd.exe session.
PowerShell, which - of necessity - has to rebuild the process command line behind the scenes on Windows after having performed argument parsing based on its rules, and - justifiably - places "R&D.txt" as verbatim R&D.txt on the process command line, given that the argument value contains no spaces.
The result is that cmd.exe interprets the unquoted R&D.txt argument on its command line as containing metacharacter &, which is its command-sequencing operator, causing the call to break.
Given that cmd.exe, the legacy Windows shell, is unlikely to receive fixes, the actively maintained PowerShell (Core) 7+ edition could as a courtesy compensate for cmd.exe's inappropriate behavior.
Doing so has been proposed in GitHub issue #15143, but, alas, it looks like these accommodations will not be implemented.

How can I pass command line parameters to a Perl script? [duplicate]

I have the following Perl script. I am trying to run it in Windows 7 using ActivePerl:
#!c:\Perl64\bin\perl.exe -w
use strict;
my $mp3splt_exe = 'c:\Program Files (x86)\mp3splt\mp3splt.exe';
my $mp3splt_args = '-o "#n #f" -g "r%[#o #N]" -f -t 6.0';
print #ARGV;
my $filename = $ARGV[0];
print "$mp3splt_exe $mp3splt_args $filename\n";
(as you can see, I am trying to create a wrapper for mp3splt :-) )
When I run it like this:
C:\Program Files (x86)\mp3splt>run_mp3splt.pl a
I get this:
Use of uninitialized value $filename in concatenation (.) or string at C:\Program Files (x86)\mp3splt\run_mp3splt.pl line 12.
c:\Program Files (x86)\mp3splt\mp3splt.exe -o "#n #f" -g "r%[#o #N]" -f -t 6.0
So, first of all, when I print #ARGV, nothing gets printed, and second of all, when I assign $filename = $ARGV[0], $filename is undef, so I get the warning.
So... what am I doing wrong? Why isn't the commandline parameter being passed to the script?
As others have pointed out perl blah.pl asdf works, while blah.pl asdf fails. This is because when you run the perl script directly, Windows realizes it must call perl, and uses the rule perl "%1", which only passes the script name to perl, not any of the parameters.
To fix this, you have to tell windows to use the rule perl "%1" %*
How to do that can be a little tedious:
Option 1
According to perlmonks, you should be able to use assoc and ftype on the commandline. In fact, if you type help ftype, it tells you how to setup perl:
assoc .pl=PerlScript
ftype PerlScript=perl.exe %1 %*
To run assoc requires cmd run as administrator on Window 7.
However, this didn't work for me. Windows ignored the association. I had to modify the registry. This may be due to the misguided advice to run the Default Programs utility on Win 7, which lets you specify the program to use for given file extensions. Unlike XP, this will not allow you to specify multiple command options (to be used in the right-click menu) -- it will only allow you to specify the program that is used when you double-click on a file (or run foo.pl from commandline).
Option 2
Modify the registry: HKEY_CLASSES_ROOT
If you've used the assoc/ftype commands, you may have entries for perl or PerlScript. As I said earlier, these will be ignored. Look for pl_auto_file, and drill down to the command:
HKCR\pl_auto_file\shell\open\command
Here the (Default) should be set to something like: "C:\Perl\bin\perl.exe" "%1"
Add the missing %* on the end of that and you should be good to go: "C:\Perl\bin\perl.exe" "%1" %*
No reboot necessary.
Option 3
If you're lazy and trusting, you can try using this as a reg file, and importing it into your registry:
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\pl_auto_file\shell\open\command]
#="\"C:\\Perl\\bin\\perl.exe\" \"%1\" %*"
This should be sufficient to make blah.pl asdf work.
I've had the problem that if I executed on Win7:
perl myprog.pl a b c
the program got the parameters (in #ARGV) correctly, but if I executed:
myprog.pl a b c
the program would NOT receive the parameters.
I searched the web for a solution and soon found that it was no ActiveState perl problem but more likely a filetype association problem in Windows (Win7), (thanks to the PerlMonks website).
However all solutions changing the
assoc .pl=Perl
and the
ftype Perl="C:\Perl\bin\perl.exe" "%1" %*
did not solve the puzzle for me. I did notice that the assoc .pl was not used somehow because if I added assoc .plx=Perl and renamed my program to myprog.plx
myprog.plx a b c
worked perfectly !
So then I read this problem on the Microsoft forum were the Win7 "feature" Default Programs was mentioned, I found the solution to my problem:
Open Default Programs by clicking the Start button , and then click "Default Programs".
Select "Associate a file type or protocol with a program" and select ".pl" and click on "Change program". There was already a Perl Command Line Interpreter specified as Recommended Programs but instead I clicked on Browse and selected the Perl.exe myself. After closing the "Associate a file type ..." screen,
myprog.pl a b c
executed like a charm, all parameters were correctly retrieved by my program.
Hope that helps...
Perl ARGV problem solution in Windows 8.1:
HKEY_CLASSES_ROOT\Applications\perl.exe\shell\open\command =
"C:\Perl\bin\perl.exe" "%1" %*
No re-boot needed.
I'm pretty sure Windows 7 doesn't understand the shebang line. What happens if you run this with perl run_mp3splt.pl a?

How can I solve this I suppose a MS PowerShell parsing error?

When I used the command below [1] to set my configuration variable MONGODB_URI, it gives an error [2].
I am using Windows PowerShell.
[1] >> heroku config:set MONGODB_URI='mongodb+srv://myprojectname:<mypassword>#cluster0.rkitj.mongodb.net/<myusername>?retryWrites=true&w=majority'
[2] The system cannot find the file specified.
'w' is not recognized as an internal or external command,
operable program or batch file.
Note: myprojectname, mypassword and myusername are placeholders for the actual value.
It looks like the heroku CLI entry point is a batch file, as implied by the wording of the error messages, which are cmd.exe's, not PowerShell's.
PowerShell doesn't take the special parsing needs of batch files (cmd.exe) into account when it synthesizes the actual command line to use behind the scenes, which involves re-quoting, using double quotes only, and only when PowerShell thinks quoting is needed.
In this case PowerShell does not double-quote (because the value contains no spaces), which breaks the batch-file invocation.
You have the following options:
You can use embedded quoting so as to ensure that the value part of your MONGODB_URI=... key-value pair is passed in double quotes; note the '"..."' quoting:
heroku config:set MONGODB_URI='"mongodb+srv://myprojectname:<mypassword>#cluster0.rkitj.mongodb.net/<myusername>?retryWrites=true&w=majority"'
Caveat: This shouldn't work, and currently only works because PowerShell's passing of arguments to external program is fundamentally broken as of PowerShell 7.1 - see this answer. Should this ever get fixed, the above will break.
If your command line doesn't involve any PowerShell variables and expressions, you can use --%, the stop-parsing symbol, which, however, in general, has many limitations (see this answer); essentially, everything after --% is copied verbatim to the target command line, except for expanding cmd.exe-style environment-variable references (e.g., %USERNAME%):
heroku config:set --% MONGODB_URI="mongodb+srv://myprojectname:<mypassword>#cluster0.rkitj.mongodb.net/<myusername>?retryWrites=true&w=majority"
If you're willing to install a module, you can use the ie function from the PSv3+ Native module (install with Install-Module Native from the PowerShell Gallery in PSv5+), which internally compensates for all of PowerShell's argument-passing and cmd.exe's argument-parsing quirks (it is implemented in a forward-compatible manner so that should PowerShell itself ever get fixed, the function will simply defer to PowerShell); that way, you can simply focus on meeting PowerShell's syntax requirements, and let ie handle the rest:
# 'ie' prepended to an invocation that uses only PowerShell syntax
ie heroku config:set MONGODB_URI='mongodb+srv://myprojectname:<mypassword>#cluster0.rkitj.mongodb.net/<myusername>?retryWrites=true&w=majority'

javac powershell classpath separator

So I'm aware that different operating systems require different classpath separators. I'm running a build of windows where CMD has been replaced with Powershell which is causing problems when using the semi-colon separator.
The command I'm trying to run begins with cmd /c to try and get it to run in command prompt instead but I think when PowerShell is parsing the whole command it sees the semi-colon and thinks that is the end!
My whole command is:
cmd /c javac -cp PATH1;PATH2 -d DESTINATION_PATH SOURCE_PATH
I have tried using a space, colon and period to no avail. Can anybody suggest a solution?
This is my first question on stackoverflow, hope the community can help and that it will eventually help others. :)
I suggest you start the process in the following way using Powershell
Start-Process cmd.exe -ArgumentList "/c javac -cp PATH1;PATH2 -d DESTINATION_PATH SOURCE_PATH" -NoNewWindow
Running javac in CMD shouldn't be required. Just put quotes around arguments that (may) contain whitespace or special characters. I'd also recommend using the call operator (&). It's optional in this case, but required if you put the executable in quotes (e.g. because the executable or path contains spaces or you want to put it in a variable).
& javac -cp "PATH1;PATH2" -d "DESTINATION_PATH" "SOURCE_PATH"
You could also use splatting for providing the arguments:
$javac = "$env:JAVA_HOME\bin\javac.exe"
$params = '-cp', "PATH1;PATH2",
'-d', "DESTINATION_PATH",
"SOURCE_PATH"
& $javac #params
javac -classpath "path1:path2:." main.java does the trick in powershell. the cmd doesn't need the doble quotes however while using powershell we need to put the quotes and it works smoothly.

#!/bin/bash equivalent in windows / specify interpreter for executable script IN the script

I don't really know which part of the described technology stack the behaviour i'm describing is actually a property of - linux, or bash/sh? but it does not really matter i guess.
Anyway, on linux, in a bash or sh shell, i can run a script marked as executable in the file system without specifying the interpreter on the shell or somewhere global, but right in first line of the file,
e.g.
#!/bin/bash
#!/usr/bin/python
or even
#!/usr/bin/gcl -f
for a common lisp implementation.
Is there a general windows, powershell or cmd.exe equivalent to this?Specifically, specifying the interpreter/command line to run the script with in the script itself, rather than on the command line or in the windows registry.
If not, what are similar options? The most similar thing I know about are shortcuts. Is there something more similar?
In Windows the file extension specifies, which programs is used to Interpret a script.
You can also specify the Interpreter like "cmd": CMD /c "c:\temp\script.cmd" or with Powershell: powershell.exe script.ps1
What you can do (in Powershell) is, to specify the Version, which is used to run the script. Use #Requires -version 3.0 in first line and it will throw error on v4 cmdlets etc.