I am learning a bit how to work with parameters in a batch-script and ended up creating some kind of template for reading arguments and setting parameters
@echo off
SetLocal EnableDelayedExpansion
set needextra=
set errstat=
set noflag=
set param_f=Not set yet
set param_g=You didn't use G-flag
:readARGS
IF [%1] == [] goto :endARGS
call :arg_%1 2> nul
IF ERRORLEVEL 1 call :arg_default %1
SHIFT
IF DEFINED needextra (
set %needextra%=%~1
SHIFT
set needextra=
)
goto :readARGS
:endARGS
echo path to directory of batch script: %~dp0
echo - noflag: !noflag!
echo - param_f: !param_f!
echo - param_g: !param_g!
EndLocal
exit /b 0
The first echo that prints the directory is important for my question (see later)
After that I create a function for each flag (arg_/flag
) and one for arguments without a flag (the arg_default
):
:arg_/f -- flag f: set param_f to value of next argument
set needextra=param_f
exit /b 0
:arg_/g -- flag g: just set the param_g to a value
set param_g=You used the G-flag
exit /b 0
:arg_default -- default, neither flag f or g: just set the noflag
echo noflag=%~1
exit /b 0
When I put everything in a batch-file, let's say C:\Users\user\scripts\params.bat
and put the directory in the path I can execute the script:
> params "just an arg"
path to directory of batch script: C:\Users\user\scritpts\
- noflag: just an arg
- param_f: Not set yet
- param_g: You didn't use G-flag
> params another /G /F "this is f"
path to directory of batch script: C:\Users\user\scritpts\
- noflag: another
- param_f: this is f
- param_g: You used the G-flag
The fact I put it in functions allows me to enter the parameters in whatever order I wish but if I put the G-flag as last I get this strange behaviour:
> params /F "this is f again" bizar /G
path to directory of batch script: C:\
- noflag: bizar
- param_f: this is f again
- param_g: You used the G-flag
The %~dp0
returns only C:\
! I tried it with other parameters, moved the batch-file to another directory, called it within the directory, the %~dp0
kept returning only C:\
. In fact each time the last argument contains a "/" the %~dp0
will behave "strangely" like in this example:
> params /G /F stranger "what happens /here"
path to directory of batch script: C:\Users\user\script\what happens \
- noflag: what happens /here
- param_f: stranger
- param_g: You used the G-flag
Can someone please explain me why this is happening? I cannot figure out why and could not find anything on the web either. I use Windows 10
I really appreciate any help you can provide.
The reason why this
works and this
doesn't work is ... that in both cases it does not work!
As Magoo points, your problem is the
shift
command. By default it shifts all the arguments, so the tenth argument is stored in%9
, the old%9
is stored in%8
... and%1
is stored in%0
, losing the reference to the current batch file.In your code you are shifting all the arguments until all are processed. This leaves the last argument inside
%0
, and at this moment things become interesting.When
%~dp0
is requested, the last argument is stored inside%0
and, as we ask for the drive and folder of the element referenced inside the argument,cmd
tries to resolve it assumming you know what you ask for and the variable contains a valid reference to a element in the file system, converts it to a absolute path and then retrieve the requested elements.And here you have faced two cases
%0
contains just a simple string without slashes or backslashes.cmd
handles it as a file name that is stored in the current active directory, so, as you request a drive and path, the drive and path of the current active directory are retrieved. In your "working" cases you end with%0
contains a string with slashes or backslashes. It is the same case that before BUT the string contains a relative path (first failing case) that is prefixed with the current active directory or with a path from the root folder (second failing case) so you end withHow can you solve it?
The easiest way to solve it could be, as proposed by Magoo, to save the value of the
%0
argument before doing any shifting of the arguments.Another option is to change
shift
commands intoshift /1
, to signal that the shifting will start at the first argument, leaving%0
unchanged.If none of this options can be used you can still retrieve a reference to the batch file from inside a subroutine
I'd suggest that
%~d0
is likely to be unreliable following aSHIFT
command, so I'd save its value at the start.Perhaps This question may be of assistance. I'd still save
~dp0
first though...