Reputation: 277
I need e fast way to insert a few rows of structured data in a bat file I've used an array called myarray to scan and "read" my values but it does not work and i don't understand why This is my code:
@echo off
set myarray[1]=myfield1#myfield2#mysubfield31;mysubfield32#myfield4
for /f "tokens=1-9 delims=#" %%a in ('echo %myarray[1]%') do (
echo field1 is %%a
echo field2 is %%b
echo field3 is %%c
echo field4 is %%d
for /f "tokens=1-9 delims=;" %%k in ('echo %%c') do (
echo subfield3 is %%k
echo subfield3 is %%l
)
)
the output is like this:
field1 is myfield1
field2 is myfield2
field3 is mysubfield31 mysubfield32
field4 is myfield4
subfield3 is mysubfield31 mysubfield32
subfield3 is
why i can't obtain simply:
subfield3 is mysubfield31
subfield3 is mysubfield32
where is the ";" used as delimeter in the second for ?
Upvotes: 1
Views: 646
Reputation: 200293
That's documented behavior, the semicolon is treated as whitespace (not by the for
loop, but by the subshell executing the echo
command). This causes the semicolon to be replaced with a space, so that echo field3 is %%c
produces the output field3 is mysubfield31 mysubfield32
. Either remove delims=;
from the inner loop, so it uses the default delimiters (space and tab), or choose a different delimiter character, and your script should work as expected. Note, however, that relying on the default delimiters in the inner loop may produce undesired results, when fields of the nested "array" contain spaces.
Proof:
Demonstration of the root cause:
for /f "tokens=*" %%a in ('echo.a#b;c#d^|find ";"') do echo _%%a_
Output: none (i.e. no semicolon found in the echoed string)
for /f "tokens=*" %%a in ('echo.a#b;c#d^|find " "') do echo _%%a_
Output: _a#b c#d_
Apparently this applies to all delimiter characters (,
, ;
, =
, space and tab), since I could reproduce this behavior with each of them.
Simplified script with an input string a#b;c#d
:
@echo off
set "foo=a#b;c#d"
for /f "tokens=1-3 delims=#" %%a in ('echo %foo%') do (
echo field1 is %%a
echo field2 is %%b
echo field3 is %%c
for /f "tokens=1-2 delims=;" %%k in ('echo %%b') do (
echo subfield3 is %%k
echo subfield3 is %%l
)
)
Output:
field1 is a
field2 is b c
field3 is d
subfield3 is b c
subfield3 is
Note the space between b
and c
in 2nd and 4th line of the output.
Same script as 2., but with delims=;
removed from the inner loop:
@echo off
set "foo=a#b;c#d"
for /f "tokens=1-3 delims=#" %%a in ('echo %foo%') do (
echo field1 is %%a
echo field2 is %%b
echo field3 is %%c
for /f "tokens=1-2" %%k in ('echo %%b') do (
echo subfield3 is %%k
echo subfield3 is %%l
)
)
Output:
field1 is a
field2 is b c
field3 is d
subfield3 is b
subfield3 is c
Note that the nested "array" b;c
(from the variable %foo%
) is now processed into the correct output (lines 4 and 5). This is, because spaces and tabs are the default delimiters in for /f
loops.
Same script as 2., but using +
as the delimiter for the nested "array":
@echo off
set "foo=a#b+c#d"
for /f "tokens=1-3 delims=#" %%a in ('echo %foo%') do (
echo field1 is %%a
echo field2 is %%b
echo field3 is %%c
for /f "tokens=1-2 delims=+" %%k in ('echo %%b') do (
echo subfield3 is %%k
echo subfield3 is %%l
)
)
Output:
field1 is a
field2 is b+c
field3 is d
subfield3 is b
subfield3 is c
Note that the 2nd output line no longer contains the bogus space, and that, again, the nested "array" is processed correctly (lines 4 and 5).
For completeness: a better solution would be to drop the echo
altogether and simply loop on a double quoted string, as foxidrive and Peter Wright suggested, because it avoids the issue entirely.
@echo off
set "foo=a#b;c#d"
for /f "tokens=1-3 delims=#" %%a in ("%foo%") do (
echo field1 is %%a
echo field2 is %%b
echo field3 is %%c
for /f "tokens=1-2 delims=;" %%k in ("%%b") do (
echo subfield3 is %%k
echo subfield3 is %%l
)
)
Another solution, proposed by dbenham, would be to enable delayed expansion and have the variable expanded at runtime:
@echo off
setlocal EnableDelayedExpansion
set "foo=a#b;c#d"
for /f "tokens=1-3 delims=#" %%a in ('echo !foo!') do (
echo field1 is %%a
echo field2 is %%b
echo field3 is %%c
for /f "tokens=1-2 delims=;" %%k in ('echo %%b') do (
echo subfield3 is %%k
echo subfield3 is %%l
)
)
An even better solution, however, would be to drop batch entirely and switch to a language that actually supports arrays, e.g. PowerShell.
Upvotes: -1
Reputation: 41234
This works:
@echo off
set myarray[1]=myfield1#myfield2#mysubfield31;mysubfield32#myfield4
for /f "tokens=1-9 delims=#" %%a in ("%myarray[1]%") do (
echo field1 is %%a
echo field2 is %%b
echo field3 is %%c
echo field4 is %%d
for /f "tokens=1-9 delims=;" %%k in ("%%c") do (
echo subfield3 is %%k
echo subfield3 is %%l
)
)
pause
Upvotes: 5
Reputation: 80033
for /f "tokens=1-9 delims=#" %%a in ("%myarray[1]%") do (
may work a tad better...
Upvotes: 1