What does this Windows bat command mean? - maven

I read the following command from the batch file to run Maven on Windows mvn.bat:
if not "_%M2_HOME:~-1%"=="_\" goto checkMBat
And
if "%#eval[2+2]" == "4" goto 4NTArgs
What does this batch script mean?
ADD 1
As I tried, it seems _%M2_HOME:~-1% returns the _ plus the last 1 letter of the environment variable "_%M2_HOME%. But what's the name of this syntax?

%VAR:~-1% gets the last character in the envvar. The first snippet verifies that the envvar M2_HOME doesn't end with \. Note: Maven's docs say,
Note: For Maven 2.0.9, also be sure that the M2_HOME doesn't have a '\' as last character.
This might be related. They probably want to prepend M2_HOME to subdir names and always include a dirsep. The variable substitution in "_%...%" is unaffected by the initial underscore. Experessing it that way just ensures that the underscore is at the beginning of the output. I can't say for certain, but it may have been expressed that way to avoid a backslashed quote, e.g. "\".
The second is not any CMD/batch that I'm familiar with. The comment (assuming this comes from mvn.bat) says "4NT shell", which I take to mean that this batch file could be run in the Take Command Console which probably has extensions to MS CMD features. For example, %#eval[...] probably does numeric evaluation in 4NT. This would effectively be a check to see if the script were running in a 4NT shell.

The first one takes the last character of %M2_HOME%, adds an underscore to the front, and checks to see if the resulting string is _\ - in short, it checks that the last character of %M2_HOME% is a backslash by using substrings.
The second one is how you determine if 4NT is installed on your computer; if it is, there will be a variable function called #eval.

I found the explanation to "_%M2_HOME:~-1%" below link. It's a variable substring operation.
http://ss64.com/nt/syntax-substring.html

Related

Running command on windows does not allow quotations

when i run a command on windows 10 command line that requires a path as one of its params, it works if the path is NOT inside a quotation, but if a path has a space in it, i need to wrap it inside quotes so that it treats as one single path, but then it complains that the file in that path does not exists.
For example:
C:/PROJECTS/desktopfiles/public/libs/cpdf/win64/cpdf.exe C:/Users/john/Documents/cat.pdf C:/Users/john/Documents/my_dog.pdf -o C:/Users/john/Documents/cat_dog_Merged.pdf
The above works,
the below doesn't (because there is a space in my dog.pdf)
C:/PROJECTS/desktopfiles/public/libs/cpdf/win64/cpdf.exe C:/Users/john/Documents/cat.pdf C:/Users/john/Documents/my dog.pdf -o C:/Users/john/Documents/cat_dog_Merged.pdf
You could try to replace spaces with a question mark. The question mark is a wildcard to match "any single character", which would be a space in your case. Like this: my?dog.pdf. Just make sure that there is no other file matching this pattern. But the system should give you some error message then (which might or might not point to the root of the problem).
Another solution that comes to my mind is a batch file that renames the files in question automatically (replacing spaces with underscores) and renames them back after the pdf merge.

Search string for trailing quote character and trim it?

I'm trying to search a string (entered by the user when prompted for a path) for a trailing quote and delete it if found.
The problem: I have a bat file that prompts the user to enter a filename and path (the first is typically done via drag/drop.) If the user enters a destination path enclosed in quotes because it contains spaces, my resulting command will look like this: compress.exe "c:\source path\"destination.zip"
That extra quote in the middle needs to go. I've found plenty of ways to search a file for a string, and I found this post here on StackOverflow that seems to apply, but doesn't seem to work in my situation.
I tried the command at the above linked path, telling it to search for \" instead of bcd, but the code expects the string it's searching to have been passed to it (as a switch) upon execution, and when I try to modify the command to search srcpath instead, the bat fails. I also tried this:
if "!srcpath:~-1"=="\"" set srcpath=!srcpath:~0,-1!
This results in: "The syntax of the command is incorrect."
How can I search a string for a trailing quote and trim it? Every method I can find doesn't seem to work when the character being searched for is the quote (slash quote: \").
I use a SLOPPY batch trick when working with paths just for this reason.
There are more elegant ways but this works just as well and I don't ever have to remember how I pulled it off.
First of all, 90% of the time.. we just want ALL quotes stripped.. that would just be:
set srcpath=%srcpath:"=%
Then tack quotes on to the front and back of your new concatenated path string.
But if you REALLY only want the trailing one.. here is my stupid bash trick..
1. Add a "? to the end of your string
2. Then delete ""? from that string
3. Then delete "? from that string
Wella! Never fails!
The trick here is that a question mark isn't a valid path char.
:: SAMPLE -- Just a trailing quote removed
set srcpath="c:\source path\"
set srcpath=%srcpath%"?
set srcpath=%srcpath:""?=%
set srcpath=%srcpath:"?=%
echo srcpath=%srcpath%
::You can use the SAME TRICK to remove a trailing backslash
Would this work for you?
SET /P "%SRCPATH=Enter the source path "
ECHO %SRCPATH%
ECHO %SRCPATH:"=%

How to reliably use `rem` within a command line without ignoring adjacent commands?

I am trying to use the rem command to place a remark in a command line that contains several commands. Here are some examples to illustrate what I mean:
echo Hello & rem.Comment & echo world!
(echo Hello & rem.Comment) & echo world!
This works perfectly fine, both echo commands in each line are executed as I expect. The . seems to modify the behaviour of the rem command so that it does not treat the remaining line as comment:
Hello
world!
If I placed a SPACE (or any other delimiter TAB, ,, ;, =) instead of the ., the remaining line and therefore the second echo would be ignored (for the second example a More? prompt appears, because the ) is part of the remark and cmd expects a closing ) because of the ():
Hello
I found out that beside ., the following characters work as well: :, /, \, [, ] and +.
What else works is escaped delimiters: ^SPACE, ^TAB, ^,, ^; and ^=.
Nevertheless, is there a secure and reliable way to do that?
I would be very glad about a solution that works for both command prompt and batch-files.
According to this external reference, the familiar syntax echo. for returning a blank line fails under certain circumstances, hence using echo( is recommended as this is the only reliable method.
However, for rem, the ( does not work, everything after rem( is not recognised as a command.
Since I am aware of a weird bug of the rem command in Windows XP (reference this external link: rem %~), I am interested in a solution that applies to Windows Vista, Windows 7 or higher.
The "weird" REM %~ "bug" is not limited to XP. It is present in all modern versions of Windows that use CMD.EXE. After reading your question, I wrote Simon of SS64 a note to give clarification on the issue. REM can also fail if variable var exists, and you have rem %var:=.
So technically, there is no guaranteed safe way to blindly use REM.
But, if you are willing to accept the fatal % expansion risk, most of your listed hacks are safe to use, but only if the line includes at least one additional command via & or &&.
REM. is never safe to use in any situation if there exists a file named REM (without extension).
The folder dividers \ and / always fail if the current folder contains a file named test.bat and you use REM\..\test.bat.
In a similar fashion, REM:\..\test.bat always fails.
Every one of the other hacks can fail stand-alone in a similar situation. For example, REM^[tab]\..\test.bat fails stand-alone, but works if concatenated with another command. This is the only type of situation I've found where +, [, ], or ^[tab] can fail.
There are additional cases where some of the other hacks can fail.
Any character in the set C (^[space], ^,, ^;, ^=) that are valid in file names can fail stand-alone if remC.bat exists. For example, the following fails stand-alone:
rem^ Fails if "rem .bat" exists
Yet they are all safe when concatenated with another command:
echo OK&rem^ This is safe
rem^ This is safe &echo OK
Temporary Update
Some of the above is wrong. Investigations are ongoing at http://www.dostips.com/forum/viewtopic.php?f=3&t=6895&p=44813#p44813.
I believe the following are the simplest forms that are guaranteed to work in all cases (disregarding invalid % expansion)
REM: At least one space (or other token delimiter) must be after :
REM\ At least one space (or other token delimiter) must be after \
REM/ At least one space (or other token delimiter) must be after /
REM^[tab] At lease one space (or other token delimiter) must be after [tab]
But I won't correct the earlier info until the dust has settled
End Temporary Update
My favorite way to use inline comments is to use impossible variables. Only dynamic pseudo variables can contain = in a name, and no variable name can ever contain two =. So I like to use %= Remark goes here =%. The beauty of this form is it can be used pretty much anywhere with impunity, as long as the comment does not contain % or :. It can even be used safely within parenthesized blocks of code.
for %%F in (*) do (
%= Comment within code block =%
%= 2nd comment within code block =%
FINDSTR /B %=Must match beginning of line=% "string" %= Search string =% "%%F" %= File to search =%
)
This variants of REM seems to be a safe way to enable the & sign in the comment part.
REM/
REM\
REM:
Despite of #dbenham's comment, I can't create any file which would iterfere with these REM variants (I tried REM.bat, REM;.bat and so on).
It's always a good idea to add a space after the REM^<char>.
The problem with %~ can't be solved, as the cmd.exe uses multiple parser phases for each line.
And the %~ error is detected in an early phase (percent expansion phase), just before the phase where a REM would be detected.
But at all, I prefere percent comments for inline comments, described by dbenham
EDIT:
I removed the carets from REM^<char> as it's doesn't matter.
Normally a REM remarks the rest of the line, as the batch parser detects the REM keyword in phase2 of the parser and switches to a specialized parser only for REM.
But when a character is appended to REM the keyword will nt be detected in phase2.
If the character is one of \/;,=+( the parser will remove it later and executes a normal REM command.
That's the cause why the command operators &, &&, |, || can be recognized in this case.
Why rem/ | break fails, but (REM/) | break works?
It's because the pipe starts two seperate cmd child processes.
With surrounding parenthesis the command will be parsed the first time in the child process.
But without parenthesis, the parent process has already parsed the REM/ and checks if the file exists (but doesn't execute it).
But when such a file exists then the parser is smart enough to remove the seperator character and detects that REM is an internal command.
This behaviour looks a bit strange.

Echo misses ^ characters when long string

I have the following command in a windows batch script
echo =%%k-16,INDIRECT.EXT^("'C:\Users\...\Analysis\[ObsStreamflow.xlsx]Sheet1'^!A%%k"^),INDIRECT.EXT^("'C:\Users\...\Analysis\[sim%%j.xlsx]Sheet1'^!B!val!"^),^=C%%k/1000,^=D%%k-B%%k,^=ABS^(E%%k^),^=(E%%k^)^^2,=^(B%%k-B10^),=Sqrt^(B%%k^),=SQRT^(D%%k^),=^(J%%k - B13^)^^2 >>t%%j.csv
where the omitted file path is 38 characters long (I don't think I'm hitting the line limits, but just in case this is the problem). This is a single line in my .bat file, shown here as multiple lines just to make things more readable.
The output is mostly correct, except that where I have ^^2, it just becomes 2 (so I have =(E1)2 and =(J1-B13)2. If I omit the Indirect.Ext text, and just have
echo =%%k-16,a1,b1,^=C%%k/1000,^=D%%k-B%%k,^=ABS^(E%%k^),^=(E%%k^)^^2,=^(B%%k-B10^),=Sqrt^(B%%k^),=SQRT^(D%%k^),=^(J%%k - B13^)^^2 >>t%%j.csv
it prints correctly, so the relevant comments show as =(E1)^2 and =(J1-B13)^2, which is what I am after.
I've not had any luck finding an answer, everything I have found just points to using ^^ to get echo to return ^. I cannot break this command into multiple lines, I need it to be a single row in csv format.
Any suggestions for a fix much appreciated, I only really need to use this for a week or so, don't need an elegant solution, just one that works. - I'm very new to bat scripts (and indeed programming in general), will keep trying different ideas in the mean time.
It's only the exclamation mark that creates the problems for you.
If at least one ! is in your line (and delayed expansion is enabled), then a second caret escape phase will be started.
In this phase quotes aren't regarded, only carets.
A small test
setlocal EnableDelayedExpansion
echo one^1
echo two^^2
echo two^^2 With exclam!
echo five^^^^^& With exclam!
Output
one1
two^2
two2 With exclam
four^& With exclam
So in your sample, you need five carets.
Four to create one caret and the last one to escape the ), as the escape of the special character is only once required.
Not sure what your specific problem is but you can use a trick in Windows to emulate echo -n (echo without a newline).
The commands:
<nul: >file.csv set /p junk=first field
<nul: >>file.csv set /p junk=,second field
>>file.csv echo ,third field
will result in a single line:
first field,second field,third field
That may make it easier for you to avoid the specific problem and, as a bonus, clean up your script so it's a little more readable (such as one field per script line).
It works because set /p var=prompt is the input command. It first outputs prompt without a newline then waits for the user to enter something, assigning it to the var environment variable.
By getting input from nul:, you basically give it an empty string so it doesn't wait. The prompt is output to file.csv without the newline.
In any case, for something this complex, I'd be bypassing cmd.exe for something a little more powerful such as the UNIX text processing tools under CygWin or MinGW (which require installation but are well worth it), or even VBScript scripts (which should be on Windows by default), where you can more easily control the output.

How to workaround doskey's special character, like $L

I got a useful tip from this post: https://stackoverflow.com/a/374363/151453 , but plagued by doskey's special characters.
(env: Windows 7 and Windows XP)
Using Visual C++ command line, we have env-vars INCLUDE and LIB. So with this doskey macro,
doskey whichinclude=for %i in ($1) do #echo.%~$INCLUDE:i
we can easily findout which .h is found first in which INCLUDE directory, really convenient.
However, this trick fails for LIB. I just CANNOT simply code a macro like:
doskey whichlib=for %i in ($1) do #echo.%~$LIB:i
Call whichlib winsock32.lib, it spouts The system cannot find the file specified.
I launch Procmon to know what happens, it reveals:
So I realize $L has special meaning for doskey, it is replaced with current drive letter when run.
Try double dollar( #echo.%~$$LIB:i ), still not working, Procmon report CMD accessing C:\echo .
Counld someone kindly help me out?
My doskey book mark: http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/doskey.mspx?mfr=true
I agree with Michael Burr's comment - you may be better off with a batch file. I generally do not use DOSKEY macros because they do not work within batch files, so it seems kind of pointless. In my mind, if a command works on the command line, it should also work within a batch file.
But... it is possible to do what you want :)
The $ only has special meaning if it is followed by a character that has special meaning to DOSKEY. The $L is interpreted as the < character (input redirection). The MS documentation implies that $$L should give a $L literal, but the documentation is not correct, as you have discovered.
The DOSKEY $ substitution happens before the normal command line parsing. The trick to embed a literal $L in your macro definition is to put an intervening character between $ and L that is not treated as special by DOSKEY, but that disappears during the normal command line parsing - The ^ works perfectly. $^ has no special meaning to DOSKEY, and ^L simply becomes L during command line parsing.
You can list the definition of your DOSKEY macros by using DOSKEY /M.
The full definition you require is whichlib=for %i in ($1) do #echo(%~$^LIB:i.
The ^ must be escaped when you define the macro. So the complete line to define the macro becomes:
doskey whichlib=for %i in ($1) do #echo(%~$^^LIB:i

Resources