Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A conundrum for the regulars, probably about mistaken file handles

4 views
Skip to first unread message

Timo Salmi

unread,
Jun 23, 2008, 6:10:36 PM6/23/08
to
This is a bit lengthy. The subtle dilemma is explained towards the end.

86} How to put each line of a text file into an environment variable?

Assume the following LFN-type test file: "My test file.txt"
line 1
line 2
line 3

5
06
line 7 Line "4" is blank, "5" and "6" are short!
line 8
line 9 ends it

Note the use of the delayed expansion method
@echo off & setlocal enableextensions enabledelayedexpansion
set myfile_=C:\_D\TEST\My test file.txt
for %%f in ("%temp%\tmp$$$.cmd") do if exist %%f del %%f
::
:: Do it
set lineNro_=
for /f "tokens=* delims=" %%r in ('type "%myfile_%"') do (
set /a lineNro_+=1
echo @set line!lineNro_!_=%%r>>"%temp%\tmp$$$.cmd"
)
for %%c in (call del) do %%c "%temp%\tmp$$$.cmd"
::
:: Display the outcome
for /L %%v in (1,1,%lineNro_%) do echo line%%v_=!line%%v_!
endlocal & goto :EOF

The output will be
C:\_D\TEST>cmdfaq
line1_=line 1
line2_=line 2
line3_=line 3
line4_=5
line5_=06
line6_=line 7 Line "4" is blank, "5" and "6" are short
line7_=line 8
line8_=line 9 ends it
Observe that the empty line was skipped, and that the exclamation mark !
does not appear because of the enabled delayedexpansion.

How about without the delayed expansion? First consider
@echo off & setlocal enableextensions disabledelayedexpansion
::
:: Make a test file
set myfile_=C:\_D\BAS\My test file2.txt
for %%f in ("%myfile_%") do if exist %%f del %%f
for %%f in (first! second third fourth) do (
echo This is the %%f line>>"%myfile_%")
echo.>>"%myfile_%"
for %%f in (sixth seventh eight ninth tenth eleventh) do (
echo This is the %%f line>>"%myfile_%")
::
for %%f in ("%temp%\tmp$$$.cmd") do if exist %%f del %%f
::
:: Do it
set lineNro_=
for /f "tokens=* delims=" %%r in ('type "%myfile_%"') do (
call :ProcessOneLine %%r)
call "%temp%\tmp$$$.cmd"
::
:: Display the outcome
for /L %%v in (1,1,%lineNro_%) do (
call echo line%%v_=%%line%%v_%%
)
::
:: Clean up
for %%f in ("%temp%\tmp$$$.cmd" "%myfile_%") do (
if exist %%f del %%f)
endlocal & goto :EOF
::
:ProcessOneLine
set /a lineNro_+=1
set row=%*
echo @set line%lineNro_%_=%row%>>"%temp%\tmp$$$.cmd"
goto :EOF

The output will be
C:\_D\BAS>cmdfaq
line1_=This is the first! line
line2_=This is the second line
line3_=This is the third line
line4_=This is the fourth line
line5_=This is the sixth line
line6_=This is the seventh line
line7_=This is the eight line
line8_=This is the ninth line
line9_=This is the tenth line
line10_=This is the eleventh line

The empty line is dropped. But in all the results are as expected,
including the exlamation mark on the first line. However, let's alter
the test file a bit:

@echo off & setlocal enableextensions disabledelayedexpansion
::
set myfile_=C:\_D\BAS\My test file2.txt
for %%f in ("%myfile_%") do if exist %%f del %%f
for %%f in (1! 2 3 4) do (
echo This is line %%f>>"%myfile_%")
echo.>>"%myfile_%"
for %%f in (6 7 8 9 10 11) do (
echo This is ine %%f>>"%myfile_%")
::
for %%f in ("%temp%\tmp$$$.cmd") do if exist %%f del %%f
::
:: Do it
set lineNro_=
for /f "tokens=* delims=" %%r in ('type "%myfile_%"') do (
call :ProcessOneLine %%r)
call "%temp%\tmp$$$.cmd"
::
:: Display the outcome
for /L %%v in (1,1,%lineNro_%) do (
call echo line%%v_=%%line%%v_%%
)
::
:: Clean up
for %%f in ("%temp%\tmp$$$.cmd" "%myfile_%") do (
if exist %%f del %%f)
endlocal & goto :EOF
::
:ProcessOneLine
set /a lineNro_+=1
set row=%*
echo @set line%lineNro_%_=%row%>>"%temp%\tmp$$$.cmd"
goto :EOF

As you'll observe, the output "is all over the place"
C:\_D\BAS>cmdfaq
@set line2_=This is line
@set line3_=This is line
@set line4_=This is line
@set line5_=This is ine
@set line6_=This is ine
@set line7_=This is ine
@set line8_=This is ine
line1_=This is line 1!
line2_=
line3_=
line4_=
line5_=
line6_=
line7_=
line8_=
line9_=This is ine 10
line10_=This is ine 11

This is a conundrum, but is probably has to do with the trailing line
number (when a single digit) in the text file being taken as a file
handle. In fact, even the test file already comes out "wrong":

This is line 1!
This is line 2
This is line 3
This is line 4

This is ine 6
This is ine 7
This is ine 8
This is ine 9
This is ine 10
This is ine 11

All the best, Timo

--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FI-65101, Finland
Useful CMD script tricks http://www.netikka.net/tsneti/info/tscmd.htm

Timo Salmi

unread,
Jun 24, 2008, 12:38:10 AM6/24/08
to
Timo Salmi <t...@uwasa.fi> wrote:
> This is a bit lengthy. The subtle dilemma is explained towards the end.
>
> 86} How to put each line of a text file into an environment variable?

A slightly updated version is at
http://www.netikka.net/tsneti/info/tscmd086.htm

All the best, Timo

--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FI-65101, Finland

Timo's FAQ materials at http://www.uwasa.fi/~ts/http/tsfaq.html

billious

unread,
Jun 24, 2008, 4:11:37 AM6/24/08
to

"Timo Salmi" <t...@uwasa.fi> wrote in message
news:TS_7k.22402$_03....@reader1.news.saunalahti.fi...


Not really sure what the object is here.

----- batch begins -------
[1]@echo off
[2]for /f "tokens=1*delims=[]" %%i in ('find /v /n "" ^<data.txt') do set
yev%%i=%%j
[3]set yev
------ batch ends --------

will show the data loaded into sequential environment variable names (other
than empty lines, obviously)

and

----- batch begins -------
[1]@echo off
[2]del tempfile.txt 2>nul
[3]for /f "tokens=1*delims=[]" %%i in ('find /v /n "" ^<data.txt') do set
yev%%i=%%j
[4]for /l %%v in (1,1,23) do if defined yev%%v (
[5]for /f "tokens=1*delims==" %%i in ('set yev') do if %%i==yev%%v
>>tempfile.txt echo %%j
[6]) else (
[7]echo\>>tempfile.txt
[8])
[9]fc tempfile.txt data.txt
------ batch ends --------

will show that the the reconstructed tempfile.txt is the same as the
original data file. Obviously the "23" in [4] is a kludge to avoid the
side-issue of counting the lines.

Here's the test data I used with each line prefixed by my customary [line
number]

----- data begins -------
[1]line 1
[2]line 2
[3]line 3
[4]
[5]5
[6]06
[7]line 7 line "4" is blank, "5" and "6" are short!
[8]line 8
[9]line 9 ends it
[10]line 10 has three ending cparens )))
[11]))line 11 has three beginning cparens
[12]line 12 has three parthesis-pairs () (())
[13]line 13 with percent-%pair%
[14]line 14 with percent-%pair% but not terminating
[15]line 15 with exclamation-!pair!
[16]line 16 with exclamation-!pair! but not terminating
[17]line 17 with amper-&pair&
[18]line 18 with amper-&pair& but not terminating
[19]line 19 with gt->pair>
[20]line 20 with gt->pair> but not terminating
[21]line 21 with lt-<pair<
[22]line 22 with lt-<pair< but not terminating
[23]line 23 has three gt-lt-pairs <> <<>>
------ data ends --------

Or perhaps the ">>filename echo..." cures the confounding "echo
possibly-ending-with-numeric>>filename" problem - which is a separate issue
seemingly having nothing to do with the object of TSCMD86.


ten.n...@virgin.net

unread,
Jun 24, 2008, 6:19:30 AM6/24/08
to

I give you this version for two reasons:
Firstly it tries to keep the task as similar to Timo's as I could.
Secondly the for loop in the 'Do it' section, (minus its last line),
should output any poison characters in the test file. Not that there'd be
much use for variables containing them but the output could still be
useful.

::----- START -----
@Echo off & Setlocal enableextensions disabledelayedexpansion
::
Set myfile_=C:\_D\BAS\My test file2.txt
Type Nul>"%myfile_%"
For %%f In (1! 2 3 4) Do >>"%myfile_%" Echo.This is line %%f
Echo.>>"%myfile_%"
For %%f In (6 7 8 9 10 11) Do >>"%myfile_%" Echo.This is ine %%f
::
If Exist "%temp%\tmp$$$.cmd" Del "%temp%\tmp$$$.cmd"
::
:: Do it
For /f "tokens=1* delims=:" %%r In ('Findstr/n .* "%myfile_%"') Do (
>>"%temp%\tmp$$$.cmd" (Echo.|Set/p "=@Set line%%r_=%%s"&Echo.)
Set lineNro_=%%r)
::
Call "%temp%\tmp$$$.cmd"
::
:: Display the outcome
:: In numerical order
For /L %%v in (1,1,%lineNro_%) Do Call Echo.line%%v_=%%line%%v_%%
Set "lineNro_="
:: In alphabetical order
Set line
::
:: Clean up
Del "%temp%\tmp$$$.cmd" "%myfile_%"
::
Endlocal & Goto :Eof
::------ END ------

Tom Lavedas

unread,
Jun 24, 2008, 12:01:53 PM6/24/08
to
On Jun 24, 12:38 am, Timo Salmi <t...@uwasa.fi> wrote:
> Timo Salmi <t...@uwasa.fi> wrote:
> > This is a bit lengthy. The subtle dilemma is explained towards the end.
>
> > 86} How to put each line of a text file into an environment variable?
>
> A slightly updated version is athttp://www.netikka.net/tsneti/info/tscmd086.htm

>
> All the best, Timo
>
> --
> Prof. Timo Salmi ftp &http://garbo.uwasa.fi/archives 193.166.120.5

> Department of Accounting and Business Finance ; University of Vaasa
> mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FI-65101, Finland
> Timo's FAQ materials at http://www.uwasa.fi/~ts/http/tsfaq.html

A straightforward approach is enclose the ECHO lines in parentheses,
as in ...

@echo off & setlocal enableextensions disabledelayedexpansion
::
set myfile_=C:\_D\BAS\My test file2.txt
for %%f in ("%myfile_%") do if exist %%f del %%f
for %%f in (1! 2 3 4) do (

(echo This is line %%f) >>"%myfile_%")


echo.>>"%myfile_%"
for %%f in (6 7 8 9 10 11) do (

(echo This is line %%f) >>"%myfile_%")


::
for %%f in ("%temp%\tmp$$$.cmd") do if exist %%f del %%f
::
:: Do it
set lineNro_=
for /f "tokens=* delims=" %%r in ('type "%myfile_%"') do (
call :ProcessOneLine %%r)
call "%temp%\tmp$$$.cmd"
::
:: Display the outcome
for /L %%v in (1,1,%lineNro_%) do (
call echo line%%v_=%%line%%v_%%
)
::
:: Clean up
for %%f in ("%temp%\tmp$$$.cmd" "%myfile_%") do (
if exist %%f del %%f)
endlocal & goto :EOF
::
:ProcessOneLine
set /a lineNro_+=1
set row=%*

(echo @set line%lineNro_%_=%row%) >>"%temp%\tmp$$$.cmd"
goto :EOF

I don't know if it 'always' works, but it certainly solves the
numbered handle redirection issue.

Tom Lavedas
===========
http://members.cox.net/tglbatch/wsh/

Timo Salmi

unread,
Jun 24, 2008, 1:45:48 PM6/24/08
to
Tom Lavedas <tglb...@cox.net> wrote:
>> Timo Salmi <t...@uwasa.fi> wrote:
>>> This is a bit lengthy. The subtle dilemma is explained towards the end.
>>> 86} How to put each line of a text file into an environment variable?
>> A slightly updated version is athttp://www.netikka.net/tsneti/info/tscmd086.htm

> A straightforward approach is enclose the ECHO lines in parentheses,
> as in ...

Thanks to all who have given useful tips so far to the subtle pitfall
observed. One won't be disappointed in here in anticipating that the
other regulars would soon find useful remedies. I'll do some further
experimenting and incorporate into the FAQ #86. A few times stepping
through errors can be even more instructive than giving a solution outright.

All the best, Timo

--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5


Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FI-65101, Finland

Timo Salmi

unread,
Jun 25, 2008, 1:20:52 AM6/25/08
to
Timo Salmi <t...@uwasa.fi> wrote:
> Tom Lavedas <tglb...@cox.net> wrote:
>>> Timo Salmi <t...@uwasa.fi> wrote:
>>>> This is a bit lengthy. The subtle dilemma is explained towards the end.
>>>> 86} How to put each line of a text file into an environment variable?
>>> A slightly updated version is
>>> at http://www.netikka.net/tsneti/info/tscmd086.htm

>
>> A straightforward approach is enclose the ECHO lines in parentheses,
>> as in ...
>
> Thanks to all who have given useful tips so far to the subtle pitfall
> observed. One won't be disappointed in here in anticipating that the
> other regulars would soon find useful remedies. I'll do some further
> experimenting and incorporate into the FAQ #86.

Done! Further experimenting confirms what has been suggested. The funny
thing is that obviously I should have been reading my own FAQ a bit more
carefully and first seen the item

82} Why does echo 9>temp.txt fail while echo 10>temp.txt works?
http://www.netikka.net/tsneti/info/tscmd082.htm

However, the discussion helped me also in adding to #82 the parenthesis
idea to complement the >>filename echo ... trick. The lesson to be
learned is to use those more regularly instead of echo ... >>filename

It seems playing around with the file handles is not without some
dangers even. The CLI got confused and I finally was forced to reboot.

0 new messages