8

I'm stuck with this : I need to merge two text files in a single tab delimited text file, on a batch script. ex :

file1:

qwer
tyui
asdf

file2:

1345
6876
8796

file3:

qwer    1345
tyui    6876
asdf    8796

All I need in fact, is a equivalent to Unix command : paste -d "\t" file1 file2 > file3

user767990
  • 115
  • 2
  • 6

3 Answers3

14
 @echo off

 set f1=1.txt
 set f2=2.txt
 set "sep=  "  % tab %

 (
   for /f "delims=" %%a in (%f1%) do (
      setlocal enabledelayedexpansion
       set /p line=
       echo(%%a!sep!!line!
      endlocal
   )
 )<%f2%

pause
goto :eof
walid2mi
  • 2,704
  • 15
  • 15
  • 1
    HO man ! It working so well ! Thank you you're my life saver. Now I'm just trying to figure, how it's working. What is this enabledelayedexpansion local var ? and how the !sep! !line! working. – user767990 Aug 12 '11 at 13:45
  • 2
    +5 :-), Absoulte impressive, I didn't know that `set /p` can read **multiple** lines from a file, and it seems to be really powerful as it can read every content without the delayed toggle technic. It's a long time ago that I see a complete new technic. – jeb Aug 12 '11 at 19:21
  • 1
    @user767990 golly it's a funny one.. That % tab % is a comment.. there are no tabs outputted.. just a double space. setlocal enabledelayedexpansion ... endlocal is a bit of a story but the setlocal aspect isn't that relevant.. The enabledelayedexpansion aspect, actually just creates normal behaviour.. !sep! is like %sep% but so it works normally. You may wonder why the brackets don't match up.. echo( could be replaced with echo/ if you want. – barlop Aug 14 '11 at 07:52
  • @user767990 The clever bit is that this kind of thing works C:\>( set /p line= & set /p line= ) – barlop Aug 14 '11 at 07:53
  • @user767990 I mean, !var! while not available by default, is more normal.. do set /? to find out about the difference between %var% and !var! – barlop Aug 14 '11 at 08:13
  • En tout cas merci Walid, bien ecrit et fort utile. – user767990 Aug 16 '11 at 13:37
  • But the EnableDelayedExpansion should be placed behind the usage of %%a, else you lose the exclamation marks. `set "f1_line=%%a" - setlocal EnableDelayedExansion - echo(!f1_line!!sep!!line!- endlocal` – jeb Aug 19 '11 at 16:10
  • @jeb the setlocal enabledelayedexpansion is only for !var! in this case !line! and !sep! so only needs to wrap that. though !sep! may as well be %sep% since it's static within the for loop. so absolutely no need for it to wrap around the %%a too. – barlop Aug 28 '11 at 03:25
  • @jeb and of course %%a is one variable that can be dynamic in that for loop, without that wrapper and of course isn't of the form !var! so wouldn't need that wrapper. – barlop Aug 28 '11 at 03:31
  • @barlop: But you need the wrapper to preserve exclamation marks, using %%a with EnableDelayedExpansion destroys them. Using !sep! instead of %sep% also works with problematic characters for the seperator like `()&|^!` – jeb Aug 28 '11 at 12:48
  • @jeb what do you mean, as an example, walid used %%a with EnableDelayedExpansion, are you saying that destroyed something? what? (assuming /v:off the default, as we are) All !var! must be within that wrapper of setlocal EnableDelayedExpansion and endlocal. And they are. And %%a works exactly the same whether within that wrapper or not, so the wrapper can be where it is within the FOR of that code and is fine there. (though it may perhaps run more efficiently if the setlocal is outside the FOR, but that's another matter!) – barlop Aug 28 '11 at 13:45
  • 1
    @barlop: nice, but wrong :-) See the difference between `@echo off setlocal DisableDelayedExpansion for %%a in ("Hello!") DO echo %%a setlocal EnableDelayedExpansion for %%a in ("Hello!") DO echo %%a ` and you can read [How the parser works](http://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts/4095133#4095133) – jeb Aug 29 '11 at 08:23
  • @jeb wow, it was more complex than I thought.. thanks. BTW, looks to me like EnableDelayedExpansion has to be after the FOR header, so as not to mess up the %%a in the for header(you'd probably agree on that), and cannot be before the echo %%a line because then it'd mess up the %%a, so hence your fix. When you say "the EnableDelayedExpansion should be placed behind the usage of %%a" Did you mean Behind !f1_line! (which is how you fixed it). – barlop Nov 26 '11 at 13:43
  • @jeb i'm wondering if you were suggesting an alternative fix to the one you did? – barlop Nov 26 '11 at 13:45
  • @barlop Added an own "answer" – jeb Nov 26 '11 at 19:21
4

The answer of walid2me is awesome, this is only a small mofication to show how to make it safe against characters like !^ in the file 1.txt, the content of file 2.txt is safe, a it is read with teh set/p syntax.

@echo off

 set f1=1.txt
 set f2=2.txt
 set "sep=  "  % tab %

 (
   setlocal DisableDelayedExpansion
   for /f "delims=" %%a in (%f1%) do (
      set "f1_line=%%a"
      setlocal EnableDelayedExpansion
       set /p f2_line=
       echo(!f1_line!!sep!!f2_line!
      endlocal
   )
   endlocal
 )<%f2%

pause
goto :eof

As you can see, I only move the expansion of %%a just before the setlocal EnableDelayedExpansion

There is still another small flaw, as set/p strips trailing control characters, like single CR, LF and also TAB.
This affects only the file 2.txt.

In depth analysis about set /p are at New technic: set /p can read multiple lines from a file

jeb
  • 78,592
  • 17
  • 171
  • 225
  • suppose it was cmd /v:on, would it be OK to put setlocal DisableDelayedExpansion before the for /f, and endlocal after set "f1_line=%%a" ? – barlop Nov 26 '11 at 21:14
  • No, then you have one endlocal per loop, but no further setlocal's, and you will destroy the `f1_line` variable with the endlocal. I edit the answer to be safe, even if DelayedExpansion was enabled – jeb Nov 26 '11 at 21:37
3

There's no native Windows command I know of that will do that, but there's a set of Unix tools for Windows here.

Carey Gregory
  • 6,836
  • 2
  • 26
  • 47