I was trying to do some operations to every file in a folder.
for %%d in (*.txt) do call:test "%%d"
pause
exit /B
:test
echo %1
Usually this works fine, but if there is a file %~aaa.txt
in the folder, it says that The following usage of the path operator in batch-parameter substitution is invalid: %~aaa.txt
.
How to make it handle this correctly? Maybe some unescaping?
The issue is that the call
command parses the command line call:test "%%d"
(which should read call :test "%%~d"
) a second time:
%%d
becomes expanded to the currently iterated file, which is %~aaa.txt
in the failing situation.%~aaa.txt
now becomes parsed another time due to the call
command, where %~
is the beginning of an argument reference, the following a
is a modifier (~a
would expand to file attributes), but there is the decimal digit missing (%~a1
or %~aaa2
were valid, for instance).To work around that, you could put the argument into a normal environment variable and read it in the sub-routine (I used delayed variable expansion therein in order to avoid troubles with special characters):
for %%d in (*.txt) do (
set "ARG=%%~d"
call :test
)
exit /B
:test
setlocal EnableDelayedExpansion
echo(!ARG!
endlocal
exit /B
You could also pass the variable name as an argument to the sub-routine:
for %%d in (*.txt) do (
set "ARG=%%~d"
call :test ARG
)
exit /B
:test
setlocal EnableDelayedExpansion
echo(!%~1!
endlocal
exit /B
Another way is to let call
expand the actual file name during its second parsing phase:
for %%d in (*.txt) do (
set "ARG=%%~d"
call :test "%%ARG%%"
)
exit /B
:test
set "STR=%~1"
setlocal EnableDelayedExpansion
echo(!STR!
endlocal
exit /B
To avoid issues with file names containing ^
, &
or other special characters, a simple echo(%~1
in the sub-routine is avoided.