我想找到一个Windows批处理对应Bash的$@,它持有传递到脚本的所有参数的列表。

还是要我费心去换班?


当前回答

上面的很多信息引导我进行了进一步的研究,最终得出了我的答案,所以我想贡献我所做的事情,希望它能帮助其他人:

我还想向批处理文件传递不同数量的变量,以便在文件中处理它们。 我可以使用引号将它们传递给批处理文件 我希望他们处理类似于下面-但使用循环而不是手动写入:

所以我想执行这个:

prog_ZipDeleteFiles.bat "_appPath=C:\Services\Logs\PCAP" "_appFile=PCAP*.?"

通过for循环的魔力在批处理文件中做到这一点:

set "_appPath=C:\Services\Logs\PCAP"
set "_appFile=PCAP*.?"

我遇到的问题是,我使用for循环的所有尝试都不起作用。下面的例子:

for /f "tokens* delims= " in %%A (%*) DO (
   set %%A
)

会这样做:

set "_appPath=C:\Services\Logs\PCAP"

而不是:

set "_appPath=C:\Services\Logs\PCAP"
set "_appFile=PCAP*.?"

即使在设置之后

SETLOCAL EnableDelayedExpansion

原因是for循环读取了整行,并在循环的第一次迭代中将第二个参数赋值给%%B。因为%*表示所有的参数,所以只需要处理一行——因此只会发生一次for循环。事实证明,这是故意的,而我的逻辑是错误的。

因此,我不再尝试使用for循环,而是通过使用if、shift和goto语句来简化我试图做的事情。同意,这有点黑,但它更适合我的需要。我可以遍历所有参数,然后在处理完所有参数后使用if语句退出循环。

我想要实现的目标是:

echo on
:processArguments
:: Process all arguments in the order received
if defined %1 then (
    set %1
    shift
    goto:processArguments
) ELSE (
    echo off 
)

更新-我不得不修改如下,当我试图引用%1并以这种方式使用shift时,我暴露了所有的环境变量:

echo on
shift
:processArguments
:: Process all arguments in the order received
if defined %0 then (
    set %0
    shift
    goto:processArguments
) ELSE (
    echo off 
)

其他回答

获取脚本中所有参数的方法如下:

@ECHO off
ECHO The %~nx0 script args are...
for %%I IN (%*) DO ECHO %%I
pause

我发现下次你需要查这些资料的时候。你不需要打开浏览器,只需要输入call /?在你的CMD,你会得到它:

...

%* in a batch script refers to all the arguments (e.g. %1 %2 %3
    %4 %5 ...)

Substitution of batch parameters (%n) has been enhanced.  You can
now use the following optional syntax:

    %~1         - expands %1 removing any surrounding quotes (")
    %~f1        - expands %1 to a fully qualified path name
    %~d1        - expands %1 to a drive letter only
    %~p1        - expands %1 to a path only
    %~n1        - expands %1 to a file name only
    %~x1        - expands %1 to a file extension only
    %~s1        - expanded path contains short names only
    %~a1        - expands %1 to file attributes
    %~t1        - expands %1 to date/time of file
    %~z1        - expands %1 to size of file
    %~$PATH:1   - searches the directories listed in the PATH
                   environment variable and expands %1 to the fully
                   qualified name of the first one found.  If the
                   environment variable name is not defined or the
                   file is not found by the search, then this
                   modifier expands to the empty string

The modifiers can be combined to get compound results:

    %~dp1       - expands %1 to a drive letter and path only
    %~nx1       - expands %1 to a file name and extension only
    %~dp$PATH:1 - searches the directories listed in the PATH
                   environment variable for %1 and expands to the
                   drive letter and path of the first one found.
    %~ftza1     - expands %1 to a DIR like output line

In the above examples %1 and PATH can be replaced by other
valid values.  The %~ syntax is terminated by a valid argument
number.  The %~ modifiers may not be used with %*

上面的很多信息引导我进行了进一步的研究,最终得出了我的答案,所以我想贡献我所做的事情,希望它能帮助其他人:

我还想向批处理文件传递不同数量的变量,以便在文件中处理它们。 我可以使用引号将它们传递给批处理文件 我希望他们处理类似于下面-但使用循环而不是手动写入:

所以我想执行这个:

prog_ZipDeleteFiles.bat "_appPath=C:\Services\Logs\PCAP" "_appFile=PCAP*.?"

通过for循环的魔力在批处理文件中做到这一点:

set "_appPath=C:\Services\Logs\PCAP"
set "_appFile=PCAP*.?"

我遇到的问题是,我使用for循环的所有尝试都不起作用。下面的例子:

for /f "tokens* delims= " in %%A (%*) DO (
   set %%A
)

会这样做:

set "_appPath=C:\Services\Logs\PCAP"

而不是:

set "_appPath=C:\Services\Logs\PCAP"
set "_appFile=PCAP*.?"

即使在设置之后

SETLOCAL EnableDelayedExpansion

原因是for循环读取了整行,并在循环的第一次迭代中将第二个参数赋值给%%B。因为%*表示所有的参数,所以只需要处理一行——因此只会发生一次for循环。事实证明,这是故意的,而我的逻辑是错误的。

因此,我不再尝试使用for循环,而是通过使用if、shift和goto语句来简化我试图做的事情。同意,这有点黑,但它更适合我的需要。我可以遍历所有参数,然后在处理完所有参数后使用if语句退出循环。

我想要实现的目标是:

echo on
:processArguments
:: Process all arguments in the order received
if defined %1 then (
    set %1
    shift
    goto:processArguments
) ELSE (
    echo off 
)

更新-我不得不修改如下,当我试图引用%1并以这种方式使用shift时,我暴露了所有的环境变量:

echo on
shift
:processArguments
:: Process all arguments in the order received
if defined %0 then (
    set %0
    shift
    goto:processArguments
) ELSE (
    echo off 
)

下面的代码模拟了一个数组('params')——接受脚本接收到的参数,并将它们存储在变量params_1 ..Params_n,其中n=params_0=数组元素的个数:

@echo off

rem Storing the program parameters into the array 'params':
rem Delayed expansion is left disabled in order not to interpret "!" in program parameters' values;
rem however, if a parameter is not quoted, special characters in it (like "^", "&", "|") get interpreted at program launch
set /a count=0
:repeat
    set /a count+=1
    set "params_%count%=%~1"
    shift
    if defined params_%count% (
        goto :repeat
    ) else (
        set /a count-=1
    )    
set /a params_0=count

rem Printing the program parameters stored in the array 'params':
rem After the variables params_1 .. params_n are set with the program parameters' values, delayed expansion can
rem be enabled and "!" are not interpreted in the variables params_1 .. params_n values
setlocal enabledelayedexpansion
    for /l %%i in (1,1,!params_0!) do (
        echo params_%%i: "!params_%%i!"
    )
endlocal

pause
goto :eof

% 1…%n和%*保存参数,但是访问它们可能很棘手,因为内容将被解释。 因此,用普通语句处理这样的事情是不可能的

myBatch.bat "&"^&

每一行都失败,因为cmd.exe试图执行一个&号(%1的内容是“&”&)

set var=%1
set "var=%1"
set var=%~1
set "var=%~1"

但是存在一个临时文件的解决方案

@echo off
SETLOCAL DisableDelayedExpansion

SETLOCAL
for %%a in (1) do (
    set "prompt=$_"
    echo on
    for %%b in (1) do rem * #%1#
    @echo off
) > param.txt
ENDLOCAL

for /F "delims=" %%L in (param.txt) do (
  set "param1=%%L"
)
SETLOCAL EnableDelayedExpansion
set "param1=!param1:*#=!"
set "param1=!param1:~0,-2!"
echo %%1 is '!param1!'

诀窍是在rem语句后启用echo并展开%1(也适用于%2 ..% *)。 但是为了能够重定向echo on的输出,您需要两个for - loop。

额外的字符* #用于安全对抗/?(有助于快速眼动)。 或者行尾的插入符号^可以作为多行字符。

FOR /F应关闭延迟展开,否则包含“!”的内容将被销毁。 在删除param1中的额外字符后,您就得到了它。

要以安全的方式使用param1,请启用延迟扩展。

编辑:一条注释到%0

%0包含用于调用批处理的命令,也像FoO.BaT中一样保留大小写 但是在调用函数%0之后,也在%~0中包含函数名(或者更好的是用于调用函数的字符串)。 但是使用%~f0,您仍然可以找回文件名。

@echo off
echo main %0, %~0, %~f0
call :myLabel+xyz
exit /b

:MYlabel
echo func %0, %~0, %~f0
exit /b

输出

main test.bat, test.bat, C:\temp\test.bat
func :myLabel+xyz, :myLabel+xyz, C:\temp\test.bat