Is there a way to indicate the last n parameters in a batch file?
在下面的示例中,我想从父批处理文件调用子批处理文件,并将所有剩余参数传递给子批处理文件。
1 2 3 | C:\> parent.cmd child1 foo bar C:\> parent.cmd child2 baz zoop C:\> parent.cmd child3 a b c d e f g h i j k l m n o p q r s t u v w x y z |
在parent.cmd中,我需要从参数列表中除去%1,只将剩余的参数传递给子脚本。
1 2 | set CMD=%1 %CMD% <WHAT DO I PUT HERE> |
我已经调查过使用带%*的轮班,但这行不通。当shift将位置参数向下移动1时,%*仍然引用原始参数。
有人有什么想法吗?我应该放弃并安装Linux吗?
遗憾的是,
1 2 3 4 5 6 7 8 9 | rem throw the first parameter away shift set params=%1 :loop shift if [%1]==[] goto afterloop set params=%params% %1 goto loop :afterloop |
我想可以做得更短,不过…我不经常写这些东西。)
不过,应该可以。
下面是一个使用"for"命令的单行方法…
1 | for /f"usebackq tokens=1*" %%i in (`echo %*`) DO @ set params=%%j |
此命令将第一个参数分配给"i",其余参数(用"*"表示)分配给"j",然后用它来设置"params"变量。
线
1 | %CMD% <WHAT DO I PUT HERE> |
应改为:
1 2 3 4 5 6 7 8 9 10 11 12 13 | ( SETLOCAL ENABLEDELAYEDEXPANSION SET skip=1 FOR %%I IN (%*) DO IF !skip! LEQ 0 ( SET"params=!params! %%I" ) ELSE SET /A skip-=1 ) ( ENDLOCAL SET"params=%params%" ) %CMD% %params% |
当然,可以将skip var设置为任意数量的参数。
说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ( @rem Starting block here, because it's read once and executed as one @rem otherwise cmd.exe reads file line by line, which is waaay slower. SETLOCAL ENABLEDELAYEDEXPANSION SET skip=1 @rem if value contains unquoted non-paired parenthesis, SET varname=value @rem confuses cmd.exe. SET"a=value" works better even if value has quotes. FOR %%I IN (%*) DO ( IF !skip! LEQ 0 ( SET"params=!params! %%I" :: newline after SET to lower amount of pitfalls when arguments :: have unpaired quotes ) ELSE ( SET /A skip-=1 ) ) ( @rem get variables out of SETLOCAL block @rem as whole block in parenthesis is read and expanded before executing, @rem SET after ENDLOCAL in same block will set var to what it was before @rem ENDLOCAL. All other envvars will be reset to state before SETLOCAL. ENDLOCAL SET"params=%params%" ) @rem doing this outside of parenthesis block to avoid @rem cmd.exe confusion if params contain unquoted closing round bracket %CMD% %params% |
你可以这样做:
1 | %* |
如果这是行中唯一的东西,那么它将扩展为让第一个参数是执行的命令,并将所有其他参数传递给它。:)
我改进了莫什·戈伦的回答,因为它似乎不适合我:
1 2 3 | set _input=%* call set params=%%_input:%1 =%% @echo %params% |
另一种方法(几乎与Alxander Bird的方法相同),不在子shell中执行echo:
1 | FOR /F"usebackq tokens=1*" %%I IN ('%*') DO SET params=%%J |
所以,行
1 | %CMD% <WHAT DO I PUT HERE> |
看起来像:
1 | FOR /F"usebackq tokens=1*" %%I IN ('%*') DO %CMD% %%J |
问题是,如果参数中包含带空格的带引号的Sting,则cmd.exe将对其进行适当的分析,以便使用带编号的参数(%1),但for将忽略引号。在这种特定情况下,如果第一个参数包含一个或多个空格,这是很可能的,因为第一个参数可以是,例如,"C:Program FilesInternet Exploreriexplore.exe"。
所以,这里还有另一个答案。
我在遇到类似问题时遇到了这个问题,但我用另一种方法解决了它。我没有使用循环(如@joey的回答)重新创建输入行,而是从输入字符串中删除了第一个参数。
1 2 3 | set _input=%* set params=!_input:%1 =! call OTHER_BATCH_FILE.cmd %params% |
当然,这假设所有参数都不同。
虽然在很多情况下,"for"的解决方案确实是更好的,但对于一些简单的问题,我经常只是保存和转移其他论点,然后像往常一样使用
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | :: run_and_time_me.cmd - run a command with the arguments passed, while also piping :: the output through a second passed-in executable @echo off set run_me=%1 set pipe_to_me=%2 shift shift :: or :: set run_me=%1 :: shift :: set pipe_to_me=%1 :: shift %run_me% %* | %pipe_to_me% |
不管怎样,我看到这个问题的答案很长,但我想我会减少我的两分钱,因为这是我没看到的东西,因为这是我需要的答案,当我几年前终于遇到它的时候…然后说"哦…"啊"