简体   繁体   中英

Batch: parameter with both expansion symbols

Question:

Is it possible to have a function receive a parameter which has both a percent sign and an exclamation mark?

Problem:

I am in a FOR /D processing directories in this fashion:

FOR /D %%d IN ("%~1\*") DO (
    CALL :process "%%~fd"
)

The problem comes when the subdirectory name ( %%~fd ) contains both a % and a ! (which is completely legal in Windows ), such as C:\\&!x#% . When I read %1 in the subprocedure :process , the percent sign disappears. If I EnableDelayedExpansion , then the exclamation mark does.

I read this post and, apparently, this cannot be solved. If delayed expansion is disabled, the % will be erased. If delayed expansion is enabled, the ! will be.

Example:

ex.bat:

@ECHO OFF
SET arg="%~1"
CALL :clean_echo %arg%
GOTO :EOF

:clean_echo
SET arg="%~1"
SET arg=%arg:&=^&%
SET arg=%arg:|=^|%
SET arg=%arg:<=^<%
SET arg=%arg:>=^>%
ECHO %arg:~1,-1%
GOTO :EOF

If I execute ex.bat "%!" the output is just ! . The % is lost when it is passed on to the :clean_echo subprocedure.

@ECHO OFF
SETLOCAL
FOR /d %%a IN (*) DO (ECHO %%~fa
 SET "var=%%~fa"
 CALL :proc var
)

GOTO :EOF

:proc
FOR /f "tokens=1*delims==" %%x IN ('set %1 2^>nul') DO IF /i "%1"=="%%x" (
 ECHO %%y
)
GOTO :eof

You don't say enough about your application, but essentially passing such strings as a parameter is doomed to fail. Here's a method that may work for you, although it won't cope with the data starting with = (I've seen filenames containing = .)

It's a game of piggy-in-the-middle with the parser being piggy. So long as your data remains assigned to a metavariable it seems fine. Really depends on the unstated - precisely what you want to do with it.

It could be done, you need to double the percents and prefix the exclamation marks with a caret.
But then it fails with single carets in the name and that can't be solved in a proper way.

As Magoo said, it's always better to use a variable and only transfer the variable name instead of the content.

But in the function you should use delayed expansion to expand the variable.

setlocal DisableDelayedExpansion

FOR /D %%d IN ("%~1\*") DO (
    set "var=%%~fd"
    setlocal EnableDelayedExpansion
    CALL :process var
    endlocal
)
exit /b

:process
set "content=!%1!"
echo !content!
exit /B

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM