如何在windows批处理脚本中以字符串形式获取可选命令行参数值?

如何在windows批处理脚本中以字符串形式获取可选命令行参数值?,windows,batch-file,Windows,Batch File,给定一个可选的端口参数,其中端口号的长度可以不同,如何从批处理脚本的命令行参数中获取端口号 例如: foo.bat --foo bar --port 80 --bar foo 应输出: 80 我走了这么远,试图使用子字符串 set CMD_LINE_ARGS=%* @rem Remove all chars and port arg set PORT_ARG_REMOVED=%CMD_LINE_ARGS:*-port =% @rem Obviously, this is where I fa

给定一个可选的端口参数,其中端口号的长度可以不同,如何从批处理脚本的命令行参数中获取端口号

例如:

foo.bat --foo bar --port 80 --bar foo
应输出:

80
我走了这么远,试图使用子字符串

set CMD_LINE_ARGS=%*
@rem Remove all chars and port arg
set PORT_ARG_REMOVED=%CMD_LINE_ARGS:*-port =%
@rem Obviously, this is where I fail to remove trailing chars
set PORT_NUM=%PORT_ARG_REMOVED: *=%
echo %PORT_NUM%
编辑

我选择的答案是因为它适合我非常特殊的用例,在这个用例中,所有参数都被传递给我正在包装的命令。而且,我只需要一个特定可选参数的值。不需要循环


这里有一些非常好的答案,用于处理可选参数解析。所以,请随意投票给每个人

对于单独的命令行参数,可以使用
%1
%2
等。在您的情况下,
--端口
将是
%3
,其值将是
%4

幸运的是,还有一个
shift
命令,它将所有参数移位为2变为1,3变为2,以此类推

这意味着您可以在一个循环中“刮取”所有命令行参数。您一直在移动,当遇到
--port
时,您知道下一个将是端口号,您可以将其存储在适当的变量中(使用
设置
)以供以后使用

如果您这样实现它,您可以实现一组可选参数,并且顺序也不重要

因此,在代码中,您的“foo.bat”可以如下所示:

@echo off
:: No parameters given? Then run ourselves with the defaults from the question.
if "%1"=="" goto none

:: Actual reading of parameters starts here.

:loop
if "%1"=="--port" set port=%2
:: Of course you need the other ifs only if you're interested in these parameters
if "%1"=="--foo" set foo=%2
if "%1"=="--bar" set bar=%2

:: Shift all parameters, except %0. Do it twice to skip the parameter and its value.
shift /1
shift /1

:: As long as there are more, keep looping. You can even parse more than 10 parameters this way!
if not "%1"=="" goto loop

:: Output what we've found
echo The specified port is %port%
echo Foo is set to %foo%
echo The bar is at %bar%
pause

exit /b

:: If no parameters are given, call ourselves with example parameters.
:none
call %0 --foo bar --port 80 --bar foo
没有只显示端口号的演示垃圾的精简版。我认为这是对您当前代码的替代

@echo off
:loop
if "%1"=="--port" set port=%2
shift /1
shift /1
if not "%1"=="" goto loop
echo %port%

鉴于您“真的很想看到子字符串工作”,以下是您的脚本结构和编码,如您所愿

@Set“CMD\u LINE\u ARGS=%*”
@Rem移除所有字符和端口arg
@设置“端口参数已删除=%CMD\u行参数:*-端口=%”
@Rem清除拖焦
@设置“端口号=%PORT\u ARG\u REMOVED:=”&:“%%”
@回显%PORT\u NUM%
@停顿

一种更简单、更明显的方法,无论参数有多少,都可以获得所有参数:

@echo off
setlocal EnableDelayedExpansion

set "arg="
for %%a in (%*) do (
   if not defined arg (
      set "arg=%%a"
   ) else (
      set "!arg:~2!=%%a"
      set "arg="
   )
)

echo foo = %foo%
echo port = %port%
echo bar = %bar%

如果您喜欢短代码,下面的版本可以用更少的行完成相同的任务:

@echo off

set "args= %*"
set "args=%args: --=+%"
set "args=%args: ==%"
set args=%args:+=&set %

echo foo = %foo%
echo port = %port%
echo bar = %bar%

如果您想查看较短版本的工作原理,只需删除
@echo off
行并执行它。

我将首先使用删除
--port
部分,然后通过a获取值,如下所示:

@echo off
:: No parameters given? Then run ourselves with the defaults from the question.
if "%1"=="" goto none

:: Actual reading of parameters starts here.

:loop
if "%1"=="--port" set port=%2
:: Of course you need the other ifs only if you're interested in these parameters
if "%1"=="--foo" set foo=%2
if "%1"=="--bar" set bar=%2

:: Shift all parameters, except %0. Do it twice to skip the parameter and its value.
shift /1
shift /1

:: As long as there are more, keep looping. You can even parse more than 10 parameters this way!
if not "%1"=="" goto loop

:: Output what we've found
echo The specified port is %port%
echo Foo is set to %foo%
echo The bar is at %bar%
pause

exit /b

:: If no parameters are given, call ourselves with example parameters.
:none
call %0 --foo bar --port 80 --bar foo
set CMD\u LINE\u ARGS=%*
@rem删除最多为“--port`+一个空间的所有内容:
设置“端口参数已删除=%CMD\u行参数:*--PORT=%
@rem提取第一个空格-(或制表符-)分隔项:
对于/F“tokens=1”%%A in(“%PORT\u ARG\u REMOVED%”)请设置“PORT\u NUM=%%A”
回显/%PORT\u NUM%
for/F方法有一个巨大的优势,即当提供多个连续空格来分隔命令行参数时,它甚至可以工作


如果希望代码允许所有标准令牌分隔符(即空格、制表符、
=
和带有代码的字符)而不仅仅是空格,则可以将代码更改为:

set“FLAG=”
@rem使用标准的“for”循环遍历参数:
对于%%A in(%*)do(
@rem捕获“--port”项后面的参数:
if defined标志if not defined PORT_NUM set“PORT_NUM=%%~A”
@rem使用'FLAG'变量延迟迭代捕获参数;
@rem要区分大小写匹配“---port”,请删除“/I”选项:
如果/I“%%~A”==”--端口“设置”标志=#”
)
回显/%PORT\u NUM%

实际上,我更喜欢这种方式,因为不涉及字符串操作,因为参数列表是按照
cmd

的性质进行解析的,我同意这是可行的。但是,它似乎做了太多的工作来避免一些我认为在批处理脚本中有效的东西。我肯定会认为这是一个答案,你可以使用一种稍微不同的方法,但是效果基本相同。也有获取子字符串的方法,但它们使用的是字符数。还有一个字符串替换,但我认为这在这里并没有什么帮助。这并不是很多工作,如果为了演示而去掉所有开销,那么只有5行代码可以得到端口号。9行代码需要一个循环(如果“if”语句为1行,则可能需要7行代码),而上面没有循环的代码只有3行。在我的方法中,您可能会争论4,但无论如何,我必须保留这两种方法中的命令行参数。只是说…我已经在答案的底部加入了简短的版本。5对于循环,7如果包括回送关闭和回送端口。但就像我说的,它不像你问题中的版本那么简单。但不同的是,这一个有效。我的印象是你在寻找一个有效的解决方案,而不一定是一个字节压缩的代码破解。我不能给你。我很讨厌短代码。哈哈。我不想为LOC争论。但是..我以前不需要检查没有争论,现在我需要了。而且,我需要一个标签跳到,如果我这样做。所以,7没有输出。嘎!对但是,你能解释第5行的语法吗?这似乎很奇怪。看起来双引号的数量不均匀,但它可以工作。更准确地说,我看到您正在搜索空格,我认为这就是为什么需要引用整个集合参数的原因。然后,通过
=“
”将其替换为空。但是,我丢失了尾随的
&:
。它实际上是将空格替换为
”&:“
,因此整行变为
@Set“PORT_NUM=80”&:”“
变量展开后;
&
允许在同一行上连接另一个命令,剩下的
:“
只不过是一个跳转标签,因此这被忽略……如果可选参数的值可以模拟参数的名称,则此技术可能会失败。例如,
foo.bat--foo--port--port 80--bar foo
将产生port=--port OP已经表示他们确信输入参数