Windows 如何从上的第n个位置获取批处理文件参数?

Windows 如何从上的第n个位置获取批处理文件参数?,windows,batch-file,Windows,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% ech

进一步了解如何通过精确指定其余参数来获取这些参数?我不想使用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

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

以下是不使用
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%

下面的代码使用了
shift
,但它避免了使用
for
解析命令行,并让命令行解释器完成这项工作(考虑到
for
没有正确解析双引号,例如参数集
ab”“C
被解释为3个参数
A
B“
”C
by
for
,但作为解释器的两个参数
A
B“C
;此行为会阻止引用的路径参数(如
“C:\Program Files\”
)被正确处理):

%therest%
中的其余参数可能与最初关于分隔符的方式不同(请记住,命令行解释器也将制表符、
=
视为分隔符以及所有组合),因为此处所有分隔符都由一个空格替换。但是,当将
%therest%
传递给其他命令或批处理文件时,它将被正确解析

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

@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
。以上是从我的dir/file模式处理批处理中提取的。不要说这不能处理
=
的参数,但至少可以使用空格和通配符引用路径

@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

还有一个选择:-)

其他一些答案没有涉及引号或参数之间的额外空格。免责声明:我没有很好地测试过这一点

这只是
%*
轮班后不更新的一个解决办法

我从@Pavel-p的技术开始将其实现为一种流行音乐

  • 它依赖批处理解析器来删除额外的空格
  • 它取决于全局变量“Params”
  • ~
    删除引号--由您根据需要重新报价。如果不需要,请删除
    ~
用法:

@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

太糟糕了,DOS没有#include

这可能无法正确处理引号内的参数。Johannes在这个问题上给出了一个可靠的答案:@Dave;这个答案旁边有什么不可靠?@PatrickCuff如果您使用带空格的引号参数运行批处理文件,输出将是错误的。请尝试以下6个选项,例如:“param 1”“param 2”和“param 3”都有多个问题。尝试转发参数,如
--path=c:\a\b\c
。请注意,它可以更好地处理这些情况。+1因为它适用于我手头上的东西,而不深入研究我可能称之为批量巫毒的东西。不过,它仍然比另一个答案更冗长,更难看出它是如何工作的。你能详细介绍一下所提到的情况吗?在这些情况下,这将比为更好地处理事情。谢谢!
FOR
实现只使用空格和制表符作为分隔符,而命令行解释器也允许使用
=(可能还有更多?)。您应该用
“tokens=1-3*”
替换部分
“tokens=1-3*delims=,;=”
,以反映这一点(
代表一个选项卡)。无论如何,解释器不会将双引号分隔符字符(例如,
”,“
)视为分隔符,但
会;因此,解释器将参数
ab“C
解释为2个参数
A
B”C
,解释器将参数
A
B
C
解释为
实现。感谢您的解释。我终于(专心地)读到了“近乎重复”的链接,看到你的答案是那里的@Joey's的一个充实版本。读者也应该阅读其他答案;使用
for
还有另一种可能有用的用法我遇到了命令行解释器和
for
变体在行为上的另一个区别:后者吸收了两倍于参数中包含的相邻插入符号
^
:使用解释器方法时,您需要至少2个
^
才能在输出中获取
^
^^^
才能获取
^
,等等。;使用
FOR
,您至少需要
^^^ ^
才能获得
^
等可能的副本
@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