如何从第 N 个位置获取批处理文件参数?

Posted

技术标签:

【中文标题】如何从第 N 个位置获取批处理文件参数?【英文标题】:how to get batch file parameters from Nth position on? 【发布时间】:2010-09-27 19:26:42 【问题描述】:

进一步How to Pass Command Line Parameters in batch file 如何通过准确指定其余参数来获得它们?我不想使用 SHIFT,因为我不知道可能有多少参数,并且如果可以的话,我想避免计算它们。

例如,给定这个批处理文件:

@echo off
set par1=%1
set par2=%2
set par3=%3
set therest=%???
echo the script is %0
echo Parameter 1 is %par1%
echo Parameter 2 is %par2%
echo Parameter 3 is %par3%
echo and the rest are %therest%

运行mybatch opt1 opt2 opt3 opt4 opt5 ...opt20 会产生:

the script is mybatch
Parameter 1 is opt1
Parameter 2 is opt2
Parameter 3 is opt3
and the rest are opt4 opt5 ...opt20

我知道%* 给出了所有参数,但我不希望没有前三个(例如)。

【问题讨论】:

Is there a way to indicate the last n parameters in a batch file?的可能重复 【参考方案1】:

以下是不使用SHIFT 的方法:

@echo off

for /f "tokens=1-3*" %%a in ("%*") do (
    set par1=%%a
    set par2=%%b
    set par3=%%c
    set therest=%%d
)

echo the script is %0
echo Parameter 1 is %par1%
echo Parameter 2 is %par2%
echo Parameter 3 is %par3%
echo and the rest are %therest%

【讨论】:

这可能无法正确处理引号中的参数。 Johannes 在这个问题上留下了可靠的答案:***.com/questions/761615/… @Dave;这个答案有什么不可靠的? @PatrickCuff 如果您使用带引号的参数运行批处理文件,其中包含空格,则输出将是错误的。试试这 6 个,例如:“param 1”“param 2”“param 3”4 5 6 两者都有多个问题。尝试转发--path=c:\a\b\c等参数。请参阅 my answer 更好地处理这些情况。【参考方案2】:

以下代码使用shift,但它避免使用for 解析命令行并让命令行解释器完成这项工作(注意for 无法正确解析双引号,例如参数集A B" "Cfor 解释为 3 个参数 AB""C,但被解释器解释为 2 个参数 AB" "C;这种行为可以防止引用的路径参数,如 "C:\Program Files\"被正确处理):

@echo off

set "par1=%1" & shift /1
set "par2=%1" & shift /1
set "par3=%1" & shift /1

set therest=
set delim=

:REPEAT
if "%1"=="" goto :UNTIL
set "therest=%therest%%delim%%1"
set "delim= "
shift /1
goto :REPEAT
:UNTIL

echo the script is "%0"
echo Parameter 1 is "%par1%"
echo Parameter 2 is "%par2%"
echo Parameter 3 is "%par3%"
echo and the rest are "%therest%"
rem.the additional double-quotes in the above echoes^
    are intended to visualise potential whitespaces

%therest% 中的其余参数可能看起来不像它们最初涉及分隔符的方式(请记住,命令行解释器还将 TAB、,;= 视为分隔符以及所有组合),因为这里所有的分隔符都被一个空格代替。但是,当将%therest% 传递给其他命令或批处理文件时,它会被正确解析。

到目前为止,我遇到的唯一限制适用于包含插入符号^ 的参数。其他限制(与<>|&" 有关)适用于命令行解释器本身。

【讨论】:

+1 因为它适用于我手头的东西,并且它没有深入研究我可能称之为批处理巫术的东西。不过,它仍然比其他答案更冗长,而且更难看出它是如何工作的。您能否详细说明一下这将比 FOR 更好地处理事情的情况? 谢谢! FOR 实现仅使用空格和制表符作为分隔符,而命令行解释器还允许 , ; =(可能还有更多?)。您应该将"tokens=1-3*" 部分替换为"tokens=1-3* delims=,;=_ " 以反映这一点(_ 代表TAB)。无论如何,解释器不会将双引号分隔符(例如," "",")视为分隔符,但 FOR 会;所以参数A B" "C被解释器解释为2个参数AB" "C,并被FOR实现解释为3个参数AB""C 感谢您的解释。我终于(注意)阅读了几乎重复的***.com/questions/761615/… 的链接,看到你的答案是那里@Joey 的充实版本。读者也应该阅读其他答案;使用for 的另一种方法可能有用 我遇到了命令行解释器和FOR变体之间的另一个行为差异:如果参数中包含相邻插入符号^,则后者吸收两倍的数量:使用解释器方法时,你至少需要2个^^才能在输出中得到^^^^^才能得到^^等;使用FOR,您至少需要^^^^ 才能获得^ 等。【参考方案3】:
@ECHO OFF
SET REST=
::# Guess you want 3rd and on.
CALL :SUBPUSH 3 %*
::# ':~1' here is merely to drop leading space.
ECHO REST=%REST:~1%
GOTO :EOF

:SUBPUSH
SET /A LAST=%1-1
SHIFT
::# Let's throw the first two away.
FOR /L %%z in (1,1,%LAST%) do (
  SHIFT
)
:aloop
SET PAR=%~1
IF "x%PAR%" == "x" (
  GOTO :EOF
)
ECHO PAR=%PAR%
SET REST=%REST% "%PAR%"
SHIFT
GOTO aloop
GOTO :EOF

我喜欢使用子程序而不是EnableDelayedExpansion。以上是从我的目录/文件模式处理批处理中提取的。不要说这不能处理带有= 的参数,但至少可以用空格和通配符做引用路径。

【讨论】:

【参考方案4】:
@echo off
setlocal enabledelayedexpansion

set therest=;;;;;%*
set therest=!therest:;;;;;%1 %2 %3 =!

echo the script is %0
echo Parameter 1 is %1
echo Parameter 2 is %2
echo Parameter 3 is %3
echo and the rest are: %therest%

这适用于带引号的参数以及具有等号或逗号的参数,只要前三个参数没有这些特殊的分隔符。

示例输出:

test_args.bat "1 1 1" 2 3 --a=b "x y z"
Parameter 1 is "1 1 1"
Parameter 2 is 2
Parameter 3 is 3
and the rest are: --a=b "x y z"

这可以通过在原始命令行 %* 中替换 %1 %2 %3 来实现。前五个分号只是为了确保只替换这些%1 %2 %3 的第一次出现。

【讨论】:

【参考方案5】:

另一种选择:-)

其他一些答案没有处理引号或参数之间的额外空格。免责声明:我没有对此进行过很好的测试。

这只是%*shift ugg 之后没有更新的解决方法!

我从@Pavel-P 的技术开始将其实现为 POP。

它依赖批处理解析器来删除多余的空格 这取决于全局变量“Params” ~ 删除引号 - 让您根据需要重新引用。如果您不想这样做,请删除 ~
:PopFirstParam
    @set varname=%~1
    @set %varname%=%~2
    @rem @echo %varname% = '!%varname%!'
    @if '%3' equ '' set Params=&goto :eof
    @call :popone %Params%
@goto :eof
:popone
    @set Params=;;;%*
    @set Params=!Params:;;;%1 =!
@goto :eof

用法:

@setlocal enabledelayedexpansion
@set Params=%*
@call :PopFirstParam P1 %Params%
@call :PopFirstParam P2 %Params%
@call :PopFirstParam P3 %Params%
@call :PopFirstParam P4 %Params%
@rem etc . . .

具体来说,我使用它来选择性地异步运行命令:

@setlocal enabledelayedexpansion
@rem set variables that decide what to be run  . . . . 

@call :RunIfDefined doNum1 "Title 1"      mycmd1.exe     some  "params"   here
@call :RunIfDefined doNum2 "MyTitle 2"    mylongcmd2.exe some  "params"   here
@call :RunIfDefined doNum3 "Long Title 3" mycmd3.exe     some  "params"   here
@goto :eof

:RunIfDefined
    @set Params=%*
    @call :PopFirstParam DefineCheck %Params%
    @if not defined %DefineCheck% goto :eof
    
    @call :PopFirstParam WindowTitle %Params%
    @call :PopFirstParam Command %Params%
    @rem %Params% should now be the remaining params (I don't care about spaces here)
    @echo start "%WindowTitle%" "%Command%" %Params%
    @start "%WindowTitle%" "%Command%" %Params%
@goto :eof
C:\test> set doNum1=yes
C:\test> set doNum3=yes
C:\test> call dothings.bat

start "Title 1" "mycmd1.exe"     some  "params"   here
start "Long Title 3" "mycmd3.exe"     some  "params"   here

太糟糕了 DOS 没有#include

【讨论】:

以上是关于如何从第 N 个位置获取批处理文件参数?的主要内容,如果未能解决你的问题,请参考以下文章

如何从字符串向量中选择第 n 个位置?

删除从第i个位置开始,长度为len的子串

shell获取第10+个位置参数

Bash 字符串处理命令

[CDQ分治][树状数组][树套树] Jzoj P3197 K大数查询

字符串s中从第i个位置起取长度为len的子串,函数返回子串链表