Batch – how to correctly assign arbitrary percent-number (%1) or percent-asterisk (%*) arguments that may contain quotes?

前端 未结 1 829
忘了有多久
忘了有多久 2021-01-05 22:13

While working on my previous question, I faced a similar issue that I was solving initially.

Actually, I spent this month in attempts to create one universal .bat he

相关标签:
1条回答
  • 2021-01-05 22:37

    You can't solve it with normal percent expansion!
    Proof:
    The sample argument is "&"&.
    To call a batch file with this argument, you have to escape the second ampersand.

    test.bat "&"^&
    

    It's not possible to handle this with normal commands, as you always get one unquoted ampersand.

    set arg=%1
    set "arg=%1"
    set arg=%~1
    set "arg=%~1"
    

    Each line will fail with an error message.

    Is there any command that will not fail with %1 or %*?
    Yes, REM can handle them proper.

    This works without erros.

    REM %1
    

    ...

    Funny, but how do you have any benefits from using a REM statement to get the content?
    First you have to enable ECHO ON to see that it really works.

    echo on
    REM %1
    

    Nice now you see the debug output

    c:\temp>REM "&"&

    Now you only need to redirect the debug output to a file.
    There are many ways that doesn't work.

    @echo on
    > arg.txt REM %1
    ( REM %1 ) > arg.txt
    call :func > arg.txt
    
    ..
    :func 
    REM %1
    

    The call redirections itself works, but in the func itself you can't access the%1anymore.
    But there is one solution to grab the output, with a
    FOR` loop

    (
        @echo on
        for %%a in (42) do (
            rem %1
        ) 
    ) > arg.txt
    

    Is it better to store the argument in a file instead of %1?
    Yes, as a file can be read in a safe way independent of the content.

    There are still some gotchas left, like /?, ^ or %%a in the argument.
    But that can all be solved.

    @echo off
    setlocal DisableDelayedExpansion
    set "prompt=X"
    setlocal DisableExtensions
    (
        @echo on
        for %%a in (4) do (
            rem #%1#
        ) 
    ) > XY.txt
    @echo off
    echo x
    endlocal
    for /F "delims=" %%a in (xy.txt) DO (
      set "param=%%a"
    )
    setlocal EnableDelayedExpansion
    set param=!param:~7,-4!
    echo param='!param!'
    

    More about the topic at
    SO:How to receive even the strangest command line parameters?
    SO:Receive multiline arguments

    And for Drag&Drop you need an even more complex solution SO:Drag and drop batch file for multiple files?

    Edit: Solution for %*
    The extensions has to be disabled, else arguments like %a--%~a will be modified.
    But without extensions the %* expansion doesn't work anymore.
    So the extensions are enabled just to expand the %* but before the FOR shows the content the extensions will be disabled.

    @echo off
    setlocal EnableExtensions DisableDelayedexpansion
    set "prompt=-"
    (
        setlocal DisableExtensions    
        @echo on
        for %%a in (%%a) do (
            rem # %*#
        )
    ) > args.tmp
    @echo off
    endlocal
    
    set "args="
    for /F "tokens=1* delims=#" %%G in (args.tmp) DO if not defined args set "args=%%H"
    setlocal EnableDelayedExpansion
    set "args=!args:~1,-4!"
    echo('!args!'
    

    This can fetch all arguments in a safe way, but for arguments from a drag&drop operations even this isn't enough, as windows have a bug (design flaw).
    A file like Documents&More can't be fetched this way.

    0 讨论(0)
提交回复
热议问题