Tom's Guide | Tom's Hardware | Tom's Games
![]() |
![]() |
![]() |
Hello all greetings from Sweden! I have created a .bat file to read the contents of data.txt
data.txt consists of three columns each seperated with a tab:
col1 col2 col3the structure of data.txt can not be changed.
So my script looks like:
for /f "tokens=1,2*" %%a in ('type data.txt') do (call :process "%%a" "%%b" "%%c")This works fine, as long as there is data in each column. If for example co1um 1 is empty then the for loop puts the data from column 2 into column 1 (everything gets moved down one step).
I would like to prevent this from happening but I guess this is how the FOR loop works. Is there a way around this without changing the structure of data.txt?
Cheers

Hi,
Depends on what the :process does.
I put this in data.txt:
one two three
four five six
eight nineI tried this in:process:
:process
echo %1 %2 %3
if %1'==' (
echo.
else echo %1
)
if %2'==' (
echo.
else echo %1
)
if %3'==' (
echo.
else echo %1
)goto :eof
Problem is, it doesn't know that seven is the first blank column so you get this:
"one" "two" "three"
"four" "five" "six"
"eight" "nine" ""
Beats me.Good luck.
If at first you don't succeed, you're about average.M2

Hi
Knowing what the Sub Process does might help
can the varables be passed as one string.ie call :Process "one two three"
:Process "four TAB six"
:Process "TAB eight nine"

Hello, thanks for your ideas! Really sorry for the long post but I didn't explain good last time =)
The reason why I can't put like this "%%a %%b %%c" is because I need control over the content in each column (will later be outputed in a certain order, that's all) and so my FOR command must be "%%a" "%%b" "%%c".
I could do "%%a %%b %%c" instead but I would then have to parse it and I think this will give the same result?
Please bare with me, here is a better example of the problem.
data.txt looks like this:col1<tab>col2<tab>col3
col1<tab>col2<tab>col3
col1<tab><tab>col3So column 2 on the last row is empty, thats fine.
I can read the first two rows without any problem but look what happens in the last row:ROW1 from data.txt
%%a=col1
%%b=col2
%%c=col3ROW2 from data.txt
%%a=col1
%%b=col2
%%c=col3ROW3 from data.txt
%%a=col1
%%b=col3
%%c=So why does the content of column 3 move into column 2 in the last row? The answer to that will make me very happy. It's really ashame I can't change the structure of data.txt it would have been easier because the FOR command seems to have a life of it's own =)

"So why does the content of column 3 move into column 2 in the last row?"
I think it's as you said originally, the FOR gets it token by token. So if there are onlt two, they become a dn b.
As you said, getting the whole row in a string would require parsing and I think you'd wind up going in circles.
Is the data STRICTLY three columns? Albeit with some empty spots?
If at first you don't succeed, you're about average.M2

This may help.
Not strictly a batch solution, but maybe a way forward.
The batch below saves the orig data.txt, makes a copy and uses CHANGE.COM, available here:
to replace every ocurrance of a 'double tab' with [tab][BLANK][tab].
:: data4.bat
@echo offcopy data.txt data4.txt
change.com data4.txt 9,9 9,"BLANK",9
cls.for /f "tokens=1,2*" %%a in ('type data4.txt') do (call :process "%%a" "%%b" "%%c")
goto :eof:process
echo %1 %2 %3
goto :eof
:: DONE
If at first you don't succeed, you're about average.M2

Would you be willing to use a language better suited for this task? Here's my test Perl script that first generates the test data file, then reads it back in and splits the lines on the tab char. Then I print it out using a debugging module so you can see each field, including the empty one.
#!/usr/bin/perl
use Data::Dumper;
open(F, '>erik.txt') or die $!;
print F "one\ttwo\tthree\n",
       "four\tfive\tsix\n",
       "seven\t\tnine\t\n";close F;
open(F, '<erik.txt') or die $!;
while(<F>) {
    chomp;
    @fields = split /\t/;
    print "\nline $.\n";
    print Dumper @fields;
}------
outputs:
line 1
$VAR1 = 'one';
$VAR2 = 'two';
$VAR3 = 'three';line 2
$VAR1 = 'four';
$VAR2 = 'five';
$VAR3 = 'six';line 3
$VAR1 = 'seven';
$VAR2 = '';
$VAR3 = 'nine';

Tack så mycket Mechanix2Go!
Thanks in Swedish Mechanix2Go, your solution works. Altought I don't understand the code.This is syntax right?:
change.com "stringold" "stringnew"So what does your code do (what do the 9's and commas do?):
change.com data4.txt 9,9 9,"BLANK",9I would have liked to have it work without any extra files (change.com) but since it works with change.com I'm happy anyway =)
FishMonger, I don't know perl so I couldn't try this but thanks for providing it! Does Perl have to be installed in users computer or how does it execute your code?

Hi
Try this without Change.com@echo off
SetLocal EnableDelayedExpansionfind /n /v "" Tabs.txt > ~Tmp1.txt
type nul > ~Tmp2.txt
for /f "tokens=*" %%a in (~Tmp1.txt) do (
set Line=%%a
set Line=!Line: =" "!
echo !Line! >> ~Tmp2.txt
)
for /f "skip=1 tokens=1-4 delims=[]" %%a in (~Tmp2.txt) do call :Process "%%b" "%%c" "%%d"
del ~Tmp?.txt
SetLocal
exit /b:Process %1 %2 %3
echo Arg1=%1
echo Arg2=%2
echo Arg3=%3
echo.
pause > nul

Usually the Perl interpretor is installed on the user's computer, but it doesn't need to be. The Perl script can be compiled into a standalone executable.

Hi dtech10! This works great but the output is not controllable; everything is placed into one single variable %1.
This is what I did:
source.txt
row1col1<tab>row1col2<tab>row1col3
row2col1<tab><tab>row2col3
row3col1<tab>row3col2<tab>row3col3output.txt with your code
"row1col1<tab>row1col2<tab>row1col3 "
"row2col1<tab><tab>row2col3 "
"row3col1<tab>row3col2<tab>row3col3 "As you can see this is very good, nothing gets moved as before. However, as you can see each row is surrounded by "" and that's because each row is contained in one variable as I mentioned before (echo:ing %1)
This means I have to parse each row, again, which of course gives the same problem as before.
So what I'm saying is THANKS =) and do you know how to better control the output from your code?
Thanks all for helping out!!

FishMonger I would like to give your script a go!
Can you give me a hint on what I need to download to be able to compile your script into an .exe? Are we talking free software still?
Cheers

Hi
Sorry I forgot to mension the space is a TABfind /n /v "" Tabs.txt > ~Tmp1.txt
type nul > ~Tmp2.txt
for /f "tokens=*" %%a in (~Tmp1.txt) do (
set Line=%%a
set Line=!Line:TAB=" "!
echo !Line! >> ~Tmp2.txt
)

First, you need to install Perl, which is free and open source.
http://www.activestate.com/Products/ActivePerl/?mp=1It's not required, but I'd recommend using an IDE, such as Komodo for writing/testing/debugging scripts. You can download and use it for a 21 day free trial.
http://www.activestate.com/Products/Komodo/?utm_source=activeperl&utm_medium=banner&utm_campaign=komodo_activeperl_pageAdditional Windows Perl ports and IDE's
http://cpan.org/ports/index.html#win32Compiling Perl scripts:
Perl2Exe
http://www.indigostar.com/perl2exe.htmPAR
http://search.cpan.org/~autrijus/PAR-0.89/lib/PAR.pm

sorry dtech10 i missed that, it works fine now. Muchas gracias all!
will you rip my head off if i asked for a small alternation of the script =)? I just noticed something obvious that I missed.
This script works fine for:
col1<tab>col2<tab>col3but does not work for:
col1<tab><tab><tab>col2<tab>col3What I was looking for was for the later to work also - that is it shouldn't matter how many TABs are inbetween as long as the content (that isn't a TAB) gets put in variables col1 col2 and col3.
Thanks FishMonger for the perl stuff I'm looking forward to learning some perl as soon as possible!

The syntax dor change.com is:
change.com filename.ext "old" "new"
[separated by SINGLE spaces]
or:
change.com filename.ext aa,bb cc,dd
[where aa bb cc dd are DECIMAL bytes]
or a combination of the two. So in my script, a [tab][tab] gets the string inserted. In the above case, BLANK.
You wi;l, of course, want to choose a string which is NOT one of you data elements.
I understand not wanting to use any third party utilities. But because of the way the batch interpreter is wired, I see no way around.
If you need to 'distribute' this script, we could include code to create change.com on the fly.
Hi FishMonger,
I got a bunch of errors when I ran your perl script.
If at first you don't succeed, you're about average.M2

Crazy question, but why so much emphasis on tabbing? Couldn't you use comma seperated values and have it be categorized by that? Just wondering...

Mechanix2Go that would be great if you could publish or point to the code for writing change.com from a .bat file (on the fly as you say).
I admit using change.com was a bit easier for me and perhaps it will be easier to adapt the script with change.com to do both my wishes:
source example1
col1<tab><tab><tab>col2<tab>col3source example2
col1<tab>col2<tab>col3/B

AKL-MFCU
Yes i know it's wierd. I use a PLC software called MEDOC. One can import a list of settings (in my case data.txt) to this program only if the structure is content<tab>content<tab>Now, the reason I want to read data.txt and parse it is because I wish to publish this data in a controlled way to another program or a report or whatever.

M2,
Are you sure you copied it correctly?
---C:\temp>dir /b
eriksson.plC:\temp>type eriksson.pl
#!/usr/bin/perl -wuse Data::Dumper;
open(F, '>erik.txt') or die $!;
print F "one\ttwo\tthree\n",
"four\tfive\tsix\n",
"seven\t\tnine\t\n";close F;
open(F, '<erik.txt') or die $!;
while(<F>) {
chomp;
@fields = split /\t/;
print "\nline $.\n";
print Dumper @fields;
}
C:\temp>eriksson.plline 1
$VAR1 = 'one';
$VAR2 = 'two';
$VAR3 = 'three';line 2
$VAR1 = 'four';
$VAR2 = 'five';
$VAR3 = 'six';line 3
$VAR1 = 'seven';
$VAR2 = '';
$VAR3 = 'nine';C:\temp>dir /b
erik.txt
eriksson.plC:\temp>type erik.txt
one two three
four five six
seven nine---
This forum is very frustrating when posting code or its output. Justin is a little over zealous about stripping the spaces and tabs.

Hi FM,
Evidently I didn't. I copied the above and it flew.
AKL,
Even if he could change to csv, he'd be back in the same can of worms with shifting tokens caused by empty cells.
eriksson,
I'll work up the bat to create change.com and get back to you.
If at first you don't succeed, you're about average.M2

Hi FM,Looks like it got filtered; probably because it had a ZIP. Could you rename to .FM and resend.
I DL'd that perl2exe and I'll fire it up asap. TY
If at first you don't succeed, you're about average.M2

Hi eriksson
Will this do for now until I figure a better way.@echo off
SetLocal EnableDelayedExpansionfind /n /v "" Tabs.txt > ~Tmp1.txt
type nul > ~Tmp2.txt
for /f "tokens=*" %%a in (~Tmp1.txt) do (
set Line=%%a
set Line=!Line: =" "!
echo !Line! >> ~Tmp2.txt
)
for /f "skip=1 tokens=1-9 delims=[]" %%a in (~Tmp2.txt) do call :Process "%%b" "%%c" "%%d" "%%e" "%%f" "%%g" "%%h" "%%i%"
del ~Tmp?.txt
SetLocal
exit /b:Process %1 %2 %3 %4 %5 %6 %7 %8 %9
set Arg1=%1
set Arg2=%2
set Arg3=%3
set Arg4=%4
set Arg5=%5
set Arg6=%6
set Arg7=%7
set Arg8=%8
set Arg9=%9
set Count=0
for /l %%a in (1,1,9) do (
if not !Arg%%a!=="" set /a Count+=1
)
if !Count! GTR 2 (
set Count=1
for /l %%a in (1,1,9) do (
if not !Arg%%a!=="" (
if !Count! LSS 4 (
set Arg!Count!=!Arg%%a!
set /a Count+=1
)
)
)
)
echo Par1=!Arg1!
echo Par2=!Arg2!
echo Par3=!Arg3!
echo.
pause > nul

Is this the expected output of your batch script?
C:\temp>dtech10.bat
Par1="one two three "
Par2=""
Par3=""Par1="four five six "
Par2=""
Par3=""Par1="seven nine "
Par2=""
Par3=""---
Here's a Perl command that outputs what I think you expected.
C:\temp>perl -F/\t/ -MData::Dumper -lane "print Dumper @F;" Tabs.txt
$VAR1 = 'one';
$VAR2 = 'two';
$VAR3 = 'three';$VAR1 = 'four';
$VAR2 = 'five';
$VAR3 = 'six';$VAR1 = 'seven';
$VAR2 = '';
$VAR3 = 'nine';

Yep I agree, it's very KEWL :)
That is the while loop I posted earlier, executed from the command line instead of the script.

FM,
Yep, for my diseased mind, simpler is better.
This thread, unlike many high milers, has prodiced more light than heat.
If at first you don't succeed, you're about average.M2

Hi Fishmonger
Not Quite.
As I explaned to Eric earlier the here is
a TAB
@echo off
SetLocal EnableDelayedExpansionfind /n /v "" Tabs.txt > ~Tmp1.txt
type nul > ~Tmp2.txt
for /f "tokens=*" %%a in (~Tmp1.txt) do (
set Line=%%a
rem The Space here is a TAB
set Line=!Line:TAB=" "!
echo !Line! >> ~Tmp2.txt
)

dtech10, FishMonger, Mechanix2Go - Thank you all for your time and effort! I have more than one solution, I'm over the moon (you can imagine)!
perl -F/\t/ -MData::Dumper -lane "print Dumper @F;" Tabs.txt
Wow Perl is effective. I have to learn more about it, googling for tutorials. It looks alot like javascript from what I've read so far - easy to follow hopefully.
Guess it will take a while until I can create my own tabs.exe, but I have time =)Simma lugnt!
Swedish for "take it easy" or translating word by word which is more fun: "Swim calmly"

Maybe we can get FM to teach a crash course.
dtech 10,
I made one small change to eliminate the:
---------- TABS.TXT
:: d10a.bat
@echo off
SetLocal EnableDelayedExpansionfind /n /v "" < Tabs.txt > ~Tmp1.txt
type nul > ~Tmp2.txt
for /f "tokens=*" %%a in (~Tmp1.txt) do (
set Line=%%a
rem The Space here is a TAB
set Line=!Line:TAB=" "!
echo !Line! >> ~Tmp2.txt
)
:: DONE
If at first you don't succeed, you're about average.M2

>> Maybe we can get FM to teach a crash course.
lol, I thought that was what I was doing; especially when I butt-in on these batch file questions. :-)

Hi
Thanks Mechanix every little bit helps.
I think I need to stop looking at the site.
Im geeting RSI from all these batch files.
Maybe I swat up a bit more and make life easier by learning Perl, VBA, anything but MsDos Batch files, even Unix Shell was easier.

![]() |
CScokets problem in C++
|
attn: dtech10 ; oneline.c...
|

This post is quite old and has been locked from receiving new replies. Please create a new posting instead.
| Ads by Google |