如何在批处理脚本中动态地为变量赋值?

时间:2016-11-18 10:46:18

标签: windows batch-file

假设循环在命令行参数数组上运行,如下所示。 现在我如何将下一个命令行值分配给循环中的变量?

FOR %%q IN (%*) DO
(
IF %%q == "abc" (
set a = //next command line value
             )
)

在linux中,这可以像

一样完成
argv=("$@");
i=0
while(($i < ${#argv[*]})); do
case "${argv[$i]}" in
abc)
  ((i++)); a="${argv[$i]}"
;;
esac
((i++))
done

我想在批处理文件中知道相同的内容。

3 个答案:

答案 0 :(得分:1)

我不会使用for循环来读取参数。正如LinuxDisciple提到的那样,不要过快地将批次与bash或csh进行比较。例如。批量创建或访问数组或散列并不容易(如果感兴趣的话,我在答案的最后添加了一些链接,在那里他们解释了它是如何可能的)。如果你真的想使用for循环,那么使用状态变量可能是你最好的选择(参见Klitos Kyriacou's answer)。

我会使用传统标签并改为批量转载

@echo off
SetLocal EnableDelayedExpansion
:check_args
REM Check if arguments left
IF "%~1%" == "" goto :EndArgs
IF "%~1" == "abc" (
    REM next argument is %2
    set var=%~2
    REM Don't forget extra shift because you already handled next argument too
    shift
    echo I just saw you gave "abc", I set var to !var! 
) ELSE (
    echo It's just a normal argument: "%~1"
)
shift
goto :check_args

:EndArgs
EndLocal
exit

正如LinuxDisciple所提到的,不要围绕&#34; =&#34;在分配变量时使用空格,它可能会产生意外结果(带有尾随空格的变量名,带有标题空间的值,......)。上面的代码会产生类似的东西(脚本叫做argum.bat):

>argum abc blabla def
I just saw you gave "abc", I set var to "blabla"
It's just a normal argument: def

>argum "just random things" abc "this is more serious"
It's just a normal argument: "just random things"
I just saw you gave "abc", I set var to "this is more serious"

以下是delayed expansion的链接。在这种情况下需要它,因为cmd-parser将IF-clauses和FOR-loops作为单个命令加载(就像它写在一行上一样)。除非使用延迟扩展,否则无法在同一命令中创建变量并从中读取变量。它还解释了我使用!var!代替%var%的原因。 我还使用%~1代替%1来删除周围的引号(&#34;)。这个link还有其他一些&#34;技巧&#34;你可以用来操纵参数和for循环变量

当然,如果你想用你的论点做一些更复杂的事情,这不是一个好的选择,因为if-else子句的大小将是。您必须使用其他方式来处理您的论点,就像我在问question时所使用的那样(请同时阅读答案)或在此question中作为答案提出的方法(也在我的问题的答案中发布链接。)

祝你好运!

PS正如所承认的那样,批量链接到阵列解决方案:

  • this tutorial中,您会看到为什么它会变得棘手&#34;使用普通数组索引
  • 另一种方法是列出字符串中的所有元素,用分隔符(主要使用空格)分隔它们并使用for /f - loop和分隔符作为分隔符进行迭代(如同你所做的那样)所做的那样)。这里的问题是你必须使用额外的变量来访问其他数组元素而不是你在迭代期间所处理的数组元素。

答案 1 :(得分:0)

使用状态变量。

setlocal
rem Undefine state variable first, in case it's defined somewhere else.
set is_abc=
for %%q in (%*) DO (
   if defined is_abc (
      set a=%%q
      set is_abc=
   ) else (
      if "%%q" == "abc" set is_abc=1
   )
)

答案 2 :(得分:0)

与J. Baoby的解决方案一样,此解决方案不使用for循环或状态变量。该解决方案也不需要延迟扩展或设置本地 在这里添加处理更多参数是很简单的;没有嵌套的IF 这解析了&#34; -a&#34;之前的值。和前面带有&#34; -b&#34;的值。然后它将其他参数分别存储在名为otherArgs的变量中,以备日后使用。

@ECHO OFF
REM make sure we don't start with unintended values
set avar=
set bvar=
set otherArgs=
:loop
REM Exit the loop when we run out of input
if "%1" == "" goto outsideOfLoop

REM ==Check for an argument which is preceded by '-a'===============
if "%1"=="-a"  set avar=%2 & shift /1 & shift /1 & goto :loop
REM ==END '-a' handling here========================================

REM ==Check for an argument which is preceded by '-b'===============
if "%1"=="-b"  set bvar=%2 & shift /1 & shift /1 & goto :loop
REM ==END -'b' handling here========================================

REM default case here
set otherArgs=%otherArgs% %1
shift /1
goto :loop
:outsideOfLoop
echo.%%avar%% is %avar%
echo.%%bvar%% is %bvar%
echo.Other arguments were: %otherArgs%

输出:

C:\Users\me>junk.bat hi there def -b BValue ef -a aValue valuebc 123 456
%avar% is aValue
%bvar% is BValue
Other arguments were:  hi there def ef valuebc 123 456

这具有消耗%I参数的副作用,但它不需要不断增加的嵌套if语句深度以处理更多参数,并且它将你的参数分开。已经从提供的其他处理过程中进行处理,如果您以后需要处理它们,则不必删除已经识别的那些。