Reputation: 53
I have a 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
But I cannot get %%A
in FOR /L
loop working as expected.
If I use a number like 1
instead of %%A
, it works just fine.
SET "stream_obj[1].id=%stream_obj[1].id%"
But the command line in FOR /L
loop is not working with:
SET "stream_obj[%%A].id=%stream_obj[%%A].id%"
Why?
When I checked with echo
, it cut the line odd at the equal sign =
. So I don't know if it has something to do with that.
Upvotes: 3
Views: 4609
Reputation: 49127
Don't use an arithmetic expression to assign a value to an environment variable. There is usually no reason to do so. Just use SET "stream_type_total=%%A"
without /A
.
There should be a space between command GOTO
and its first argument :EOF
.
But the main problem is the command block:
( ENDLOCAL
FOR /L %%A IN (1,1,%stream_type_total%) DO (
CALL SET "stream_obj[%%A].id=%stream_obj[%%A].id%"
)
)
The command ENDLOCAL does not only restore previous state of delayed environment variable expansion, it discards also the currently active environment variables list and restores previous list of environment variables. Read this answer for details about the commands SETLOCAL and ENDLOCAL.
So the environment variable stream_type_total
as well as all stream_obj[x].id
environment variables do not exist anymore after this command.
I suggest to modify this command block to:
FOR /L %%A IN (1,1,%stream_type_total%) DO CALL SET "stream_obj[%%A].id=%stream_obj[%%A].id%"
ENDLOCAL
Now the FOR loop should work as expected.
But please note that even with this change the modified stream_obj[x].id
environment variables do not exist anymore after command ENDLOCAL.
So better would be to avoid usage of SETLOCAL and ENDLOCAL in this subroutine completely like with using this code:
: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
The commands commented out with command REM are not modified in code above.
Another solution would be using one more subroutine:
: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
The commands commented out with command REM are modified in code above too.
One last hint: Don't use comparison operator EQU
on comparing two strings. This operator is designed for comparing 32-bit signed integer values and not for string comparisons. Read the answer on Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files for details about comparing strings or integer values with command IF.
Upvotes: 2
Reputation: 82337
If you try to get more than one value out of a setlocal scope, you can't use a loop/call the way you tried.
I see two different solutions.
1) Rescue one value in each loop by leaving the setlocal scope and reenter it.
But then you also lose all other variables like stream_count
2) Use a endlocal
block with one aggregated variable for all your vars to resuce.
Like
set "rescue=%stream_obj[1].id%:%stream_obj[2].id%:%stream_obj[3].id%"
See also
exit function and preserve variable over endlocal barrier
Macro to return multiple variables across endlocal barriers
Upvotes: 0