directly quoting %~dp0 does not ignore spaces in file path - batch-file

i have a script which 3 arguments, two of which are paths. I would like to call it from a .bat file.
python myscript.py "%~dp0inputs/" "%~dp0outputs/" "foo"
If i call a dummy script that simply prints argv using the above line, i get the expected results, even for paths containing spaces:
myscript.py
C:\path\containing spaces\inputs/
C:\path\containing spaces\outputs/
foo
however if i use this (ie %~dp0 for argument 1 with nothing else between the quotes):
python myscript.py "%~dp0" "%~dp0outputs/" "foo"
then it behaves oddly when the path contains spaces:
myscript.py
C:\path\containing spaces" C:\path\containing
spaces\outputs/ foo
it seems that the quotes have not been processed properly - what have i done wrong?

It is because the quotes are passed into the python script.
And %~dp0 ends with a \ character.
Python figures that \ escapes the double quote - fun.
So, "%~dp0" is passed to the script as
"C:\temp\containing spaces\"
Python treats that trailing \ as escaping the quote, so it merges the arguments.
It shouldn't do that - but it does.
You can remove the trailing \, or add another.
Either of these works:
python myscript.py "%~dp0/" "%~dp0outputs/" "foo"
python myscript.py "%~dp0\" "%~dp0outputs/" "foo"

try to use Set to call your paths within batch. (example below)
#echo off
set myscrpt="C:\path\containing spaces\mypythonscript.py"
set mypath1="C:\path\containing spaces\inputs"
set mypath2="C:\path\containing spaces\outputs"
pushd C:\Python27
Python %myscrpt% %mypath1% %mypath2%
pause>NUL
exit

Related

how to pass "=" as part of argument to .cmd or .bat file from bit-bash for windows

in git-bash shell that I have open in windows10, this test
./test.cmd 123=456
returns
123
Contents of test.cmd are :
echo %1
I've tried ./test.cmd 123\=456 and 123^456 and doesn't work.
If I run ./test.cmd 123=456 from a cmd shell, it works fine and outputs 123=456.
I can escape other special characters, just not =
$ ./test.bat "123^^^&456"
C:\Users\551527>echo 123&456
123&456
551527#S29C0N4 MINGW64 ~
$ ./test.bat "123^^^=456"
C:\Users\551527>echo 123
123
What's so different about = ?
First problem: the equal sign is a delimiter in cmd.exe
If you start a batch file with a delimiter character this simply splits arguments.
myBatch.bat three;argu=ments
-- %1 = three
-- %2 = argu
-- %3 = ments
-- %* = three;argu=ments
To avoid the splitting you have to use quotes (carets doesn't work here).
myBatch.bat "three;argu=ments"
-- %1 = "three;argu=ments"
-- %~1 = three;argu=ments
Second problem: git-bash works different with arguments
bash has different rules for arguments, it decides what is a single argument and removes surrounding quotes
Using
./myBatch.bat "three;argu=ments"
is parsed by bash, a single argument is detected and then cmd.exe is called with this single argument like:
cmd /c myBatch.cmd three;argu=ments
At this point, it's obvious that you can't build a complex command line, that works for cmd.exe and also from bash.
It's possible to build solutions for concrete problems, but it's always a pain.

How can I use nested quotes when calling a powershell script within a batch file?

I have a DOS batch file that has a line that executes a powershell script. First I tried a very simple script with this line in the batch file:
powershell -command "get-date" < nul
That worked great. But the script has nested double-quote characters, which can sometimes be escaped with a backtick (`) character. So then I tried this:
powershell -command "Write-Host `"hello world`"" < nul
That also worked great. However, the script I need to run is pretty complicated and has more than one level of nested double-quote characters. I have taken the complicated script and simplified it to an example that has the same principles here:
[string]$Source = " `"hello world`" ";
Write-Host $Source;
If I save this script inside a PS script file and run it, it works fine, printing out “hello world” including the double quotes, but I need to embed it in the line in the batch file. So I take the script and put it all on one line, and try to insert it into the batch file line, but it doesn’t work. I try to escape the double-quotes, but it still doesn’t work, like this:
powershell -command "[string]$Source = `" `"hello world`" `";Write-Host $Source;" < nul
Is there a way to do what I want? You might ask why I am doing this, but it’s a long story, so I won’t go into the details.
thanks
You'll have to use a combination of batch's escape character and PowerShell's escape character.
In batch, when escaping quotes, you use the common shell backslash (\) to escape those quotes. In Powershell, you use the backtick `.
So if you wanted to use batch to print out a quoted string with Powershell, you need to first batch escape the quote to declare the variable in Powershell, then to ensure the string is quoted you need batch and Powershell escape another quote, and then your add your desired string, ensuring you batch escape first.
For your example, this will work:
powershell -command "[string]$Source = \"`\"hello world`\"\"; Write-Host $Source;"
Here's a break down of the declaration of the $Source variable:
"[string]$Source = # open quote to begin -command parameter declaration
\" # batch escape to begin the string portion
`\" # Powershell+Batch escape
hello world # Your content
`\" # Posh+Batch again
\"; # Close out the batch and continue
more commands " # Close quote on -command parameter
This renders the string like this in batch:
`"hello world`"
One note, you don't need to explicitly cast $Source as a string since you are building it as a literal string from scratch.
$Source = "string stuff" will work as intended.

Batch file: <part of command line> was unexpected at this time

Trying to execute a command inside a batch file and drop the result into a variable.
Here's what I would execute interactively:
curl -d "username=someUser" http://someServer/trusted
The result is a 15-20 character alpha-numeric string.
Here's my attempt at doing same in a batch file:
FOR /f %AA IN('curl -d \"username=someUser\" http://someServer/trusted') DO ECHO %AA
Error returned is:
//someServer/Trusted') was unexpected at this time
I thought I was dealing with some sort of escaping issue, so I added the \ symbols in front of my quotes. From what I've read, the : symobol in http doesn't need to be escaped, but it's interesting to me that's where the failure appears to "start".
Any ideas on this? I'm on Win8.1, FYI
for-variables have one-char-variables (%A instead of %AA)
you missed a space between IN and (
in a batch-file you have to double the percent-signs for the for-variable (%%A instead of %A)
echo handles only one line, blanks brake it, you would need to pipe it maybe?

Open Cygwin on a path passed as the first parameter to bash.exe

I'm going mad trying to achieve this. I read a lot of questions over Stack Overflow, but they didn't work. I'm trying to open a tab on console2 that opens Cygwin on the path passed as a parameter to it.
For cmd.exe, is quite easy:
cmd.exe %1
For Cygwin, this looks really hard:
bash --login -i -c 'cd `cygpath \'D:\Program Files\'`;exec bash'
The problem here is that with path without spaces it works well, with spaces, it doesn't work. Also, I don't know how to pass a param to it, maybe $1 or %1?
Edit 1:
I'm almost there, I created this batch file that should be run instead of bash.exe directly:
#echo off
set CHERE_INVOKES=%CD%
set TORUN="D:\Program Files\Cygwin\bin\bash.exe" --login -i -c 'cd "%CHERE_INVOKES%"; exec bash'
echo %TORUN%
call %TORUN%
PAUSE
This works with all paths except C: (and D:), the reason? Windows is stupid, and instead of having a path called C:, it has a path called C:!!! So, while all paths ends without a backslash, the first path ends with it, driving me mad!
The following command works for me:
c:\cygwin\bin\bash --login -i -c "cd '%~1'; exec /bin/bash.exe"
Where %~1 expands %1 removing any surrounding quotes (") — see help for in command prompt.
See also: chere package in Cygwin, and ConEmu terminal :)
Here is the solution:
#echo off
set CHERE_INVOKES=%CD%
::Remove trailing slash if required
IF %CHERE_INVOKES:~-1%==\ SET CHERE_INVOKES=%CHERE_INVOKES:~0,-1%
set TORUN="D:\Program Files\Cygwin\bin\bash.exe" --login -i -c 'cd "%CHERE_INVOKES%"; exec bash'
call %TORUN%
I added this code from this question: Remove Trailing Slash From Batch File Input
::Remove trailing slash if required
IF %CHERE_INVOKES:~-1%==\ SET CHERE_INVOKES=%CHERE_INVOKES:~0,-1%
In this way I can use this batch file to open Console2 Cygwin on the current path.

How to include pipe character in an argument to a batch file from a bash script?

I have a shell script that I want to execute this line:
qtvars.bat vsstart "qt.sln" /BUILD "Debug|Win32"
This works fine (though I had to modify qtvars.bat, but that's beside the point). The problem is that I want the command to execute to be in a variable:
EDIT: This doesn't work either, if I type it into bash. Previously I was typing it into cmd.exe, which hardly made for a fair comparison.
command="qtvars.bat"
args="vsstart"
$command $args "qt.sln" /BUILD "Debug|Win32"
Now it chokes on the pipe! I get this message:
'Win32' is not recognized as an internal or external command,
operable program or batch file.
I've tried a bunch of forms of escaping the quotes and/or pipe, all to no avail. Interestingly, it works when it's an executable rather than a batch file, e.g.:
command="devenv.exe"
args=""
$command $args "qt.sln" /BUILD "Debug|Win32"
Thanks for any ideas.
I know you "escape" the pipe character in a batch file with the ^ character, so...
echo ^| Some text here ^|
Would display...
| Some text here |
I don't know whether that would help you in this instance? Maybe try prepending each pipe character with a ^ and see what happens? :-)
This is a classic case of double-escaping, where both bash and CMD.EXE need to be instructed to ignore the special | (pipe) character.
Try the following:
$command $args "qt.sln" /BUILD '"Debug|Win32"'
This will be the equivalent of you typing, at a CMD.EXE prompt:
qtvars.bat vsstart qt.sln /BUILD "Debug|Win32"
Using the above, you are essentially forcing the passing of the double-quotes on to CMD.EXE (instead of bash eating them away.) The outermost single quotes instruct bash not to interpret or touch in any way what's inside them; the inner double-quotes instruct CMD.EXE to ignore any special characters (the pipe in this case) within.
Alternatively, you can also try:
$command $args "qt.sln" /BUILD 'Debug\|Win32'
This should be the equivalent of you typing, at a CMD.EXE prompt:
qtvars.bat vsstart qt.sln /BUILD Debug\|Win32
Note the use of single quotes (!), which ensure that bash will not interpret the \ (and, instead, will pass it as-is to CMD.EXE.)
Here's another solution (workaround?) I've found:
first, ensure an environment variable defines the pipe character, for example:
set PIPE="|"
later, run the command specifying the above defined environment variable name:
"c:\(...)\devenv.com" foo.sln /build Debug%PIPE%Win32
That does the job even if there are multiple wrappers between the caller and the callee. I'm now using it with a very long chain of wrappers:
Python/Linux -> VirtualBox guest's executeProcess -> Cmd/Windows -> devenv.com
(cross posted to: How to pass a quoted pipe character to cmd.exe?)
Escaping a piping character in the Windows scripting language is done with a caret (^). I just had to do this the other day. I know this is old, but I thought I would post what I found in case others ran across this, like I did.
I'd consider going the easy route, and passing a placeholder-token instead - "$P", and then replace it within the CMD/Batch file; e.g. using the 'UnxUtils' SEd command to do the replacement:
For /F "usebackq delims=" %%r in (`Echo %Cmd% ^| sed -e "s/$P/|/g"`) do #Set Cmd2=%%r
REM Now run the command, with the proper pipe symbol in place
%Cmd2%
So having passed the command arg/CMD script args - "git status $P wc -l".
Interesting! What does escaping the | do?
Do these work?
echo "Debug|Win32"
echo "qt.sln" /BUILD 'Debug|Win32'

Resources