Windows batch file: pathname with "&" interpreted as two commands - windows

I have a batch file which gets its own short pathname (to eliminate spaces, which gcc doesn't like) for use in subsequent commands:
set base=%~d0%~sp0
This works fine for most cases; for example, if the batch file is located in C:\Program Files, the value of %base% will be C:\PROGRA~1, and gcc is happy.
However, it doesn't work if the batch file is in a directory with "&" in the name. If it is in a directory called "C:\Here & There", the command above expands to
set base=C:\HERE&T~1\
which is treated as two commands, producing the error message 'T~1\' is not recognized as an internal or external command, operable program or batch file.
If I put quotes around it:
set base="%~d0%~sp0"
Then the command works, and the value of %base% is "C:\HERE&T~1\" (including the quotes). But then the quotes break something else further on in the file when I use it to build a Java classpath:
java -cp .;"C:\HERE&T~1\"Jars\* foo
which says "The system cannot find the file specified" (relating to "C:\HERE&T~1\"Jars\* in the classpath).
Can anyone suggest a way around this Microsoft mess?
[Edit]
As requested by Mofi below, here is a minimal reproducible example batch file:
#echo off
set base=%~d0%~sp0
echo %base%
If this is executed in a directory called "C:\Here & There", I would like the output to be
C:\HERE&T~1
without quotes or other extraneous output.
Here is the actual output when using CMD.EXE as the shell:
'T~1\' is not recognized as an internal or external command,
operable program or batch file.
C:\HERE
If I change the line #echo off to #echo on to show the commands as they are executed, I get this (where "C:\Here & There>" is the prompt, followed by the actual command being echoed prior to execution):
C:\Here & There> set base=C:\HERE & T~1\
'T~1\' is not recognized as an internal or external command,
operable program or batch file.
C:\Here & There> echo C:\HERE
C:\HERE

Since the quotes should not be part of the value, the correct SET command would be
set "base=%~d0%~sp0"

There are two problems, the first is the expansion in the SET command.
It can be avoided by quotes around the expression.
set "base=%~dps0"
The second problem is the echo, it can be avoided by quotes, too.
echo "%base%"
But then the quotes are visible, too.
In a batch file, this can be solved with delayed expansion:
set "base=%~dps0"
setlocal EnableDelayedExpansion
echo !base!
But on the command line, the delayed expansion mode can not be modified by setlocal, it can only be set by the /v:on option when cmd.exe starts
cmd /v:on
set "base=%~dps0"
echo !base!

Related

How do I create the Windows Equivalent of This Very Small Shell Script?

I'm trying to achieve the following but in a .bat file. It executes all arguments after the first one, after having set the path.
# Add your local node_modules bin to the path for this command
export PATH="./node_modules/.bin:$PATH"
# execute the rest of the command
exec "$#"
I've got the first part (I think) but don't know how to do the second part, and have not been successful in Googling the solution.
REM Add your local node_modules bin to the path for this command
SET PATH=.\node_modules\.bin;%PATH%
The first command line could be:
#set "PATH=%~dp0node_modules\.bin;%PATH%"
This command line adds to local PATH environment variable at beginning the path of subdirectory .bin in subdirectory node_modules in directory of the batch file instead of the current directory.
%~dp0 expands always to the batch file directory path ending with a backslash. For that reason %~dp0 should be always concatenated with a folder/file name without an additional backslash as done here.
It would be possible to use %CD%\ instead of %~dp0 to add the path of subdirectory .bin in subdirectory node_modules in the current directory to local PATH environment variable. But please be aware that current directory can be always different to batch file directory and is for that reason most likely not good here.
%CD% expands to a directory path string not ending with a backslash, except the current directory is the root directory of a drive in which case %CD% expands to drive letter + colon + backslash. Therefore the usage of %CD% would require the command line:
#if not "%CD:~-1%" == "\" (set "PATH=%CD%\node_modules\.bin;%PATH%") else set "PATH=%CD%node_modules\.bin;%PATH%"
The second command line could be:
#%*
That very short command line results in getting interpreted all arguments passed to the batch file with exception of argument 0 as command line to execute by Windows command processor after parsing it. See also: How does the Windows Command Interpreter (CMD.EXE) parse scripts?
# at beginning of a command line results in Windows command processor cmd.exe processing the batch file does not output the command line after parsing it. The command line with command set and with %* do not need anymore # at beginning of the line with #echo off at top of the batch file.
#echo off
set "PATH=%~dp0node_modules\.bin;%PATH%"
%*
Open a command prompt, run call /? and read the output help explaining how batch file arguments can be referenced in a batch file.
See also SS64.com which has a reference for Windows CMD and Linux Shell commands.

Can't run .bat files properly (Windows 10)

Here is my test.bat
#!/bin/bash
#set the STRING variable
SET STRING=Hello World
#Print the contents of the variable to the screen
echo $STRING
pause
When I run test.bat on Windows 10 I get this output:
C:\Workspace\mcc-batch-jobs>#!/bin/bash
'#!' is not recognized as an internal or external command,
operable program or batch file.
C:\Workspace\mcc-batch-jobs>#set the STRING variable
'#set' is not recognized as an internal or external command,
operable program or batch file.
C:\Workspace\mcc-batch-jobs>SET STRING=Hello World
C:\Workspace\mcc-batch-jobs>#Print the contents of the variable to the screen
'#Print' is not recognized as an internal or external command,
operable program or batch file.
C:\Workspace\mcc-batch-jobs>echo $STRING
$STRING
C:\Workspace\mcc-batch-jobs>pause
Press any key to continue . . .
I can't figure it out. I've checked my PATH, installed cygwin, looked over several Stackoverflow posts, and can't seem to get the script to work. The script was created as a simple test and nothing more.
From my comment, this is a batch file for Windows, (it usually has a .cmd extension but may use .bat instead):
#ECHO Off
SET "STRING=Hello World"
REM Print the contents of the variable to the screen
ECHO %STRING%
PAUSE

starting a bat script from bash under windows

I am trying to start a .bat file from gow bash. I can sucessfully start a batch and return to bash with the following (I am in C:\tmp\a\ directory), the content of the file a.bat file consists a single command cd (to print the current working directory):
$ cat a.bat
cd
$ cmd "/C a.bat"
c:\tmp\a>cd
c:\tmp\a
$
Now if I try to start the program from c:\tmp (one level higher in the hierarchy of directory structure), I get an error:
$ cmd "/C a\\a.bat"
'a' is not recognized as an internal or external command,
operable program or batch file.
$ cmd '/C a\a.bat'
'a' is not recognized as an internal or external command,
operable program or batch file.
$ cmd '/C a/a.bat'
'a' is not recognized as an internal or external command,
operable program or batch file.
How can I start a batch script given a path to it, and return to bash?
I guess I found a very simple solution:
Add a dot before /C
cmd ". /C a\a.cmd"
After that gow (and cygwin and alikes) stop treating the argument as containing paths and converting it to POSIX paths.
And cmd ignores everything up to /C (well, almost everything, I think).
a.cmd:
#echo off
echo it's working
output:
bash-3.1$ cmd ". /C a\a.cmd"
it's working
bash-3.1$
[Update]
After some research I found that POSIX path conversion has a very clean description of conversion rules.
In your case the rule An argument with a leading / is converted up to the first /.. seems to be applied.
Conversion results in changing '\' to '/'. So, you get a/a.cmd, that is a with a switch /a.cmd. And this results in the observed error, of course.
The link above addresses MSYS and seems to be a bit outdated, but I've checked some of the rules in bash from my fresh Git for Windows installation (based on MSYS2), and they look working as described.
After a bit of research and posting questions to other forums I found the following additional info to run the job "correctly":
cmd //D . //C "a\a.cmd"
References:
Github issue #244, Unix to Windows path translation may corrupt command switches/arguments
Github issue #243, when bash starts a cmd, it adds a buggy double quote symbol at the end of the line

How to start a windows batch file with variables from another batch file

I have tried the following:
set SOME_PATH="C:\some_path"
start "some program" %SOME_PATH%\pathToScript\anotherBatch.bat %SOME_PATH%\pathToConfig\some.properties
My aim is to start "anotherBatch.bat" which takes the path to a config file as an argument: %SOME_PATH%\pathToConfig\some.properties
Unfortunatley, I got an error in the new command prompt that my syntax for the file name is incorrect.
What is the right syntax for the start command above?
You should Call a batch file instead of Start one.
Set "SOME_PATH=C:\some_path"
Call "%SOME_PATH%\pathToScript\anotherBatch.bat" "%SOME_PATH%\pathToConfig\some.properties"
Where anotherBatch.bat will use %1 or "%~1" as the quoted argument and %~1 as the unquoted argument.

How to create batch file in Windows using "start" with a path and command with spaces

I need to create a batch file which starts multiple console applications in a Windows .cmd file. This can be done using the start command.
However, the command has a path in it. I also need to pass paramaters which have spaces as well. How to do this?
E.g. batch file
start "c:\path with spaces\app.exe" param1 "param with spaces"
Actually, his example won't work (although at first I thought that it would, too). Based on the help for the Start command, the first parameter is the name of the newly created Command Prompt window, and the second and third should be the path to the application and its parameters, respectively. If you add another "" before path to the app, it should work (at least it did for me). Use something like this:
start "" "c:\path with spaces\app.exe" param1 "param with spaces"
You can change the first argument to be whatever you want the title of the new command prompt to be. If it's a Windows app that is created, then the command prompt won't be displayed, and the title won't matter.
Escaping the path with apostrophes is correct, but the start command takes a parameter containing the title of the new window. This parameter is detected by the surrounding apostrophes, so your application is not executed.
Try something like this:
start "Dummy Title" "c:\path with spaces\app.exe" param1 "param with spaces"
start "" "c:\path with spaces\app.exe" "C:\path parameter\param.exe"
When I used above suggestion, I've got:
'c:\path' is not recognized a an internal or external command, operable program or batch file.
I think second qoutation mark prevent command to run. After some search below solution save my day:
start "" CALL "c:\path with spaces\app.exe" "C:\path parameter\param.exe"
Interestingly, it seems that in Windows Embedded Compact 7, you cannot specify a title string. The first parameter has to be the command or program.
You are to use something like this:
start /d C:\Windows\System32\calc.exe
start /d "C:\Program Files\Mozilla
Firefox" firefox.exe start /d
"C:\Program Files\Microsoft
Office\Office12" EXCEL.EXE
Also I advice you to use special batch files editor - Dr.Batcher
Surrounding the path and the argument with spaces inside quotes as in your example should do. The command may need to handle the quotes when the parameters are passed to it, but it usually is not a big deal.
I researched successfully and it is working fine for me. My requirement is to sent an email using vbscript which needs to be call from a batch file in windows. Here is the exact command I am using with no errors.
START C:\Windows\System32\cscript.exe "C:\Documents and Settings\akapoor\Desktop\Mail.vbs"

Resources