【问题标题】:Parsing sets of variables from a string in a bat file从 bat 文件中的字符串解析变量集
【发布时间】:2016-02-01 21:40:49
【问题描述】:

我有一种情况,我试图将相关项目的静态列表保存在字符串中,并将它们作为 bat 文件中的集合解析出来。

SET RootPath=C:\Users\woodh\test\
SET FromPath=StuffFrom\
SET ToPath=StuffTo\
SET CTLNames='text1.txt,red_text1:text2.txt,white_text2:text3.txt,blue_text3:'

CTLNames 包含要在作业中解析和使用的条目对。

我做了以下

:Step20
rem -----------------------------------------------------------------
rem loop thru all files in the control list processing each pair at a time
rem -----------------------------------------------------------------
    FOR /F "delims=:" %%f IN (%CTLNames%) DO (

        IF NOT "%%f" == "" (

            CALL:BreakEntry "%%f"
        )
    )

:Finish
rem ----------------------------------------------------------------
rem -- Finish
rem ----------------------------------------------------------------
      goto end

:BreakEntry
rem -----------------------------------------------------------------
rem loop thru all files in the control list processing each entry one at a time
rem -----------------------------------------------------------------
    Set EntryLine=%~1

    IF NOT "%EntryLine%" == "" (

        ECHO %EntryLine%

        FOR /F "tokens=1,2 delims=," %%a IN ("%EntryLine%") DO (

            ECHO %%a
            ECHO %%b

            CALL:MoveThisFile %%a, %%b
        )

    )

goto:eof

但它只处理第一对名称,而不是继续处理列表的其余部分。

【问题讨论】:

  • CTLNames 中的 : 是否必须分隔对(而 , 分隔一对元素)?
  • 批处理不是结构化语言,因此我不会费心阅读这个可怕的批处理代码(在另一种语言中可能很漂亮,但不是批处理)。但是您可能需要打开ENABLEDELAYEDEXPANSION(请参阅setlocal /?)。请参阅您的变量!var!。请参阅for /? 了解详细信息(并解释原因)。
  • @bgalea - IMO rem 语句应该在标签上方,有很多不必要的空行,命令不需要全部上限,但它是完全合理的批次。
  • 您应该从SET CTLNames='...' 命令行中删除单引号',因为它成为变量值的一部分,因此您需要处理它们,并且它们在无论如何都要批处理;最好在整个表达式周围加上双引号 ",例如 SET "CTLNames=...",以避免某些特殊字符出现问题,并且它们 not 会成为变量值的一部分...

标签: string loops parsing batch-file


【解决方案1】:

您的问题令人困惑。您没有解释代码的确切用途或预期输出,所以我们只能猜测。所以我猜你有一系列用冒号分隔的值对,并且每对值都用逗号分隔。这样,您的代码的问题在于,当仅处理 一个字符串 时,for /F 命令不会 迭代多个值:该字符串被相应地划分为“令牌和delims" 选项并且命令被执行一次。您需要使用不同的方法来处理字符串中的所有子字符串。

我会这样做:

@echo off
setlocal

SET "CTLNames=text1.txt,red_text1:text2.txt,white_text2:text3.txt,blue_text3:"

for %%f in ("%CTLNames::=" "%") do (
   for /F "tokens=1,2 delims=," %%a in (%%f) do (

      echo %%a
      echo %%b

      echo CALL :MoveThisFile %%a, %%b
   )
)

我建议你删除@echo off 行并执行程序,这样你就可以查看到底执行了什么。

【讨论】:

  • 我喜欢!谢谢!我有几个要重写的工作,其中有很多步骤可以用它来代替,从而使代码更易于维护。
【解决方案2】:

它不能按预期工作的原因(它只打印第一对),是因为for /f 在行上工作; CTLNames 仅包含一行,因此需要单次迭代。

令人困惑的部分是它仍然打印第一对...那是因为它实际上进行了拆分(在第一对 :)但默认情况下for 只关心第一对 token(在 delim 之前)并丢弃其余部分。您可以通过将行更改为来说服自己:

FOR /F "tokens=* delims=:" %%f IN (%CTLNames%) DO (

您会看到%%f 的值(因为我们指示它考虑所有令牌)是整行。

我问 COLON(:) 是否必须作为对之间的分隔符的原因是因为你也可以iterate over a non numeric list - 没有/f 标志, 但在这里您不能指定分隔符,因此您必须使用常规分隔符:SPACE( ), COMMA(,), SEMICOLON(;)、TAB,也许还有其他(无论如何 COLON 不是其中之一) - 所以这个循环:

for %%f in (text1.txt:red_text1 text2.txt:white_text2 text3.txt:blue_text3;) do (
    echo %%f
)

- 请注意,我在for 循环中使用了 3 个分隔符:TABSPACESEMICOLON(不确定它的可见度) -

会产生:

text1.txt:red_text1

text2.txt:white_text2

text3.txt:blue_text3

或者您可以在任何地方使用常规分隔符,并完全放弃对的概念,但我不知道这是否是您想要的。

我无法使用 COLON 作为单个 for 循环的分隔符来解决问题,但我能够找到一种方法。这是您的脚本(稍作修改):

@ECHO OFF

rem ECHO %CTLNames%

CALL :Step20 "%CTLNames%"
GOTO :eof

:Step20
rem -----------------------------------------------------------------
rem loop thru all files in the control list processing each pair at a time
rem -----------------------------------------------------------------
    IF "" == "%~1" GOTO :eof
    FOR /F "tokens=1* delims=:" %%f IN ("%~1") DO (
        rem echo f: %%f
        CALL :BreakEntry "%%f"
        CALL :Step20 "%%g%
    )
GOTO :eof

:BreakEntry
rem -----------------------------------------------------------------
rem loop thru all files in the control list processing each entry one at a time
rem -----------------------------------------------------------------
    Set EntryLine=%~1
    ECHO %EntryLine%
    FOR /F "tokens=1,2 delims=," %%a IN ("%EntryLine%") DO (
        ECHO %%a
        ECHO %%b
        rem CALL :MoveThisFile %%a, %%b
    )
GOTO :eof

主要的是(除了其他小的变化)Step20 是一个递归函数(标签),它使用for 循环来分割行,它处理第一个标记,然后它在剩余的令牌(直到没有剩余)。

注意:CTLNames 周围的单引号应该去掉。

【讨论】:

    猜你喜欢
    • 2011-05-15
    • 1970-01-01
    • 2021-06-23
    • 2020-01-12
    • 1970-01-01
    • 1970-01-01
    • 2017-11-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多