为什么批处理文件中的FOR / L不能按预期工作?

时间:2018-04-10 06:12:46

标签: batch-file

我有一个批处理文件:

:extract_stream
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "delims=" %%A IN ('%media_info% "--output=%stream_count_string%" "%file%"') DO SET /A "stream_type_total=%%A"

SET /A "stream_count=1"

FOR /F "tokens=1-4 delims=," %%A IN ('%media_info% "--output=%format_string%" "%file%"') DO (
    SET /A "id=%%A-1"
    SET "title=%%B"
    SET "codec=%%C"
    SET "language=%%D"

    REM SET "id=!id:~1!"
    SET "title=!title:~1!"
    SET "codec=!codec:~1!"
    SET "language=!language:~1!"

    IF NOT DEFINED language SET "language=English"
    REM IF "!codec!" EQU "V_MPEG4/ISO/AVC" SET "language="

    SET stream_obj[!stream_count!].id=!id!

    ECHO ID:!id! Title=!title!, Codec=!codec!, Lamguage=!language!

    SET /A "stream_count+=1"
)
(  ENDLOCAL
    FOR /L  %%A IN (1,1,%stream_type_total%) DO (
        CALL SET "stream_obj[%%A].id=%stream_obj[%%A].id%"
    )
)
GOTO:EOF

但我无法在%%A循环中FOR /L按预期工作。

如果我使用1而不是%%A这样的数字,那就可以了。

SET "stream_obj[1].id=%stream_obj[1].id%"

但是FOR /L循环中的命令行无效:

SET "stream_obj[%%A].id=%stream_obj[%%A].id%"   

为什么?

当我使用echo进行核对时,它会在等号=处切割奇数行。所以我不知道它是否与此有关。

2 个答案:

答案 0 :(得分:1)

不要使用算术表达式为环境变量赋值。通常没有理由这样做。只需使用SET "stream_type_total=%%A"而不使用/A

命令GOTO与其第一个参数:EOF之间应该有一个空格。

但主要问题是命令块:

(  ENDLOCAL
    FOR /L  %%A IN (1,1,%stream_type_total%) DO (
        CALL SET "stream_obj[%%A].id=%stream_obj[%%A].id%"
    )
)

命令 ENDLOCAL 不仅会恢复延迟环境变量扩展的先前状态,还会丢弃当前活动的环境变量列表并恢复以前的环境变量列表。有关命令 SETLOCAL ENDLOCAL 的详细信息,请阅读this answer

因此,在此命令之后,环境变量stream_type_total以及所有stream_obj[x].id环境变量不再存在。

我建议将此命令块修改为:

FOR /L %%A IN (1,1,%stream_type_total%) DO CALL SET "stream_obj[%%A].id=%stream_obj[%%A].id%"
ENDLOCAL

现在 FOR 循环应该按预期工作。

但请注意,即使进行此更改,修改后的stream_obj[x].id环境变量在命令 ENDLOCAL 后也不再存在。

最好避免在此子例程中使用 SETLOCAL ENDLOCAL ,就像使用此代码一样:

:extract_stream
FOR /F "delims=" %%A IN ('%media_info% "--output=%stream_count_string%" "%file%"') DO SET "stream_type_total=%%A"

SET "stream_count=1"

FOR /F "tokens=1-4 delims=," %%A IN ('%media_info% "--output=%format_string%" "%file%"') DO (
    SET /A "id=%%A-1"
    SET "title=%%B"
    SET "codec=%%C"
    SET "language=%%D"

    REM SET "id=!id:~1!"
    CALL SET "title=%%title:~1%%"
    CALL SET "codec=%%codec:~1%%"
    IF DEFINED language CALL SET "language=%%language:~1%%"

    IF NOT DEFINED language SET "language=English"
    REM IF "!codec!" EQU "V_MPEG4/ISO/AVC" SET "language="

    CALL SET "stream_obj[%%stream_count%%].id=%%id%%"

    CALL ECHO ID:%%id%% Title=%%title%%, Codec=%%codec%%, Language=%%language%%

    SET /A "stream_count+=1"
)

FOR /L %%A IN (1,1,%stream_type_total%) DO CALL SET "stream_obj[%%A].id=%stream_obj[%%A].id%"
GOTO :EOF

使用命令 REM 注释掉的命令在上面的代码中被 修改。

另一种解决方案是再使用一个子程序:

:extract_stream
FOR /F "delims=" %%A IN ('%media_info% "--output=%stream_count_string%" "%file%"') DO SET "stream_type_total=%%A"

SET "stream_count=1"

FOR /F "tokens=1-4 delims=," %%A IN ('%media_info% "--output=%format_string%" "%file%"') DO CALL :UpdateVariables "%%~A" "%%~B" "%%~C" "%%~D"

FOR /L %%A IN (1,1,%stream_type_total%) DO CALL SET "stream_obj[%%A].id=%stream_obj[%%A].id%"
GOTO :EOF

:UpdateVariables
SET /A "id=%~1-1"
SET "title=%~2"
SET "codec=%~3"
SET "language=%~4"

REM SET "id=%id:~1%"
SET "title=%title:~1%"
SET "codec=%codec:~1%"
IF DEFINED language SET "language=%language:~1%"

IF NOT DEFINED language SET "language=English"
REM IF "%codec%" == "V_MPEG4/ISO/AVC" SET "language="

SET "stream_obj[%stream_count%].id=%id%"

ECHO ID:%id% Title=%title%, Codec=%codec%, Language=%language%

SET /A "stream_count+=1"
GOTO :EOF

使用命令 REM 注释掉的命令也会在上面的代码中修改。

最后一个提示:在比较字符串时不要使用比较运算符EQU。此运算符用于比较32位有符号整数值,而不是用于字符串比较。请阅读Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files上的答案,了解有关使用命令 IF 比较字符串或整数值的详细信息。

答案 1 :(得分:0)

如果您尝试从setlocal范围中获取多个值,则无法以您尝试的方式使用循环/调用。

我看到两种不同的解决方案 1)通过离开setlocal范围并重新输入,在每个循环中挽救一个值。 但是你也失去了所有其他变量,比如stream_count

2)使用带有一个聚合变量的endlocal块来减少所有变量。 喜欢

设置“rescue =%stream_obj [1] .id%:%stream_obj [2] .id%:%stream_obj [3] .id%”

另见
exit function and preserve variable over endlocal barrier
Macro to return multiple variables across endlocal barriers